6.1.178-rc1 review
Subsystems (6)
Greg Kroah-Hartman
maintainerPATCH 663/1067 irqchip/ts4800: Fix missing chained handler cleanup on remove
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qingshuang Fu <[email protected]>
[ Upstream commit 98bf7e54cec07d514b3575c11896a8b12d50ecc4 ]
The driver installs a chained handler for the parent interrupt during probe using irq_set_chained_handler_and_data(), but the remove function does not clear this handler. This leaves a dangling handler that may be called when the parent interrupt fires after the driver has been removed, potentially accessing freed memory and causing a kernel crash.
Additionally, the parent_irq obtained via irq_of_parse_and_map() is not stored, making it inaccessible in the remove function. Moreover, interrupt mappings created during probe are not properly disposed.
Fix this by:
- Saving parent_irq in probe
- Clearing the chained handler with NULL in ts4800_ic_remove()
- Disposing all IRQ mappings before domain removal to prevent resource leaks
--- drivers/irqchip/irq-ts4800.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/irqchip/irq-ts4800.c +10 -0
@@ -28,6 +28,7 @@ struct ts4800_irq_data {void __iomem *base;struct platform_device *pdev;struct irq_domain *domain; +unsigned int parent_irq; };static void ts4800_irq_mask (struct irq_data *d)
@@ -134,6 +135,7 @@ static int ts4800_ic_probe(struct platform_device *pdev)irq_set_chained_handler_and_data (parent_irq, ts4800_ic_chained_handle_irq, data); + data->parent_irq = parent_irq;platform_set_drvdata (pdev, data);return 0 ;
@@ -142,6 +144,14 @@ static int ts4800_ic_probe(struct platform_device *pdev)static int ts4800_ic_remove (struct platform_device *pdev) {struct ts4800_irq_data *data =platform_get_drvdata (pdev); +unsigned int hwirq; + +irq_set_chained_handler_and_data (data->parent_irq,NULL ,NULL ); + +for (hwirq =0 ; hwirq <8 ; hwirq++) +irq_dispose_mapping (irq_find_mapping (data->domain, hwirq)); + +irq_dispose_mapping (data->parent_irq);irq_domain_remove (data->domain);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 664/1067 virtio_net: disable cb when NAPI is busy-polled
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Longjun Tang <[email protected]>
[ Upstream commit 1eb8fc67ca41db71c90866ff76c990d85247daef ]
When busy-poll is active, napi_schedule_prep() returns false in virtqueue_napi_schedule(), so virtqueue_disable_cb() is skipped. The device may keep firing irqs until reaches virtqueue_napi_complete(). Under load (received == budget), it will lead to a large number of spurious interrupts.
Fix it by disabling the callback at the virtnet_poll() entry. This keeps the callback off while we poll and it is re-enabled by virtqueue_napi_complete() when going idle.
--- drivers/net/virtio_net.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/net/virtio_net.c +3 -0
@@ -1709,6 +1709,9 @@ static int virtnet_poll(struct napi_struct *napi, int budget)unsigned int received;unsigned int xdp_xmit =0 ; +if (budget) +virtqueue_disable_cb (rq->vq); +virtnet_poll_cleantx (rq, budget); received =virtnet_receive (rq, budget, &xdp_xmit);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 665/1067 cxgb4: Fix decode strings dump for T6 adapters
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Gleb Markov <[email protected]>
[ Upstream commit 5d6dc22d62682d93f5f55f145ad792f2891de911 ]
Depending on the value of chip_version, the correct decode set is selected. However, the subsequent matching with the t4 encoding type in the if-else block results in a reassignment, which leads to the loss of support for t6_decode as well as reinitializing of values t4_decode and t5_decode.
The component history shows that the if-else block previously used for this purpose, as well as the execution order, was not affected by the change.
Furthermore, it is suggested by the execution order that the scenario with overwriting and loss of support will be implemented.
Delete the if-else block.
--- drivers/net/ethernet/chelsio/cxgb4/t4_hw.c | 8 -------- 1 file changed, 8 deletions(-)
drivers/net/ethernet/chelsio/cxgb4/t4_hw.c +0 -8
@@ -6737,14 +6737,6 @@ void t4_sge_decode_idma_state(struct adapter *adapter, int state)return ; } -if (is_t4 (adapter->params.chip)) { - sge_idma_decode = (const char **)t4_decode; - sge_idma_decode_nstates =ARRAY_SIZE (t4_decode); - }else { - sge_idma_decode = (const char **)t5_decode; - sge_idma_decode_nstates =ARRAY_SIZE (t5_decode); - } -if (state < sge_idma_decode_nstates)CH_WARN (adapter,"idma state %s\n" , sge_idma_decode[state]);else
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 666/1067 net/sched: act_bpf: use rcu_dereference_bh() to read the filter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sechang Lim <[email protected]>
[ Upstream commit adc49c7ba690c9b33b8392ec27397456b65d0893 ]
tcf_bpf_act() can run from the tc egress path, which holds only rcu_read_lock_bh(), but reads prog->filter with rcu_dereference() and trips lockdep:
WARNING: suspicious RCU usage
net/sched/act_bpf.c:47 suspicious rcu_dereference_check() usage! 1 lock held by syz.2.1588/12756:
#0: (rcu_read_lock_bh){....}-{1:3}, at: __dev_queue_xmit net/core/dev.c:4792
tcf_bpf_act+0x6ae/0x940 net/sched/act_bpf.c:47 tcf_classify+0x6e4/0x1080 net/sched/cls_api.c:1860 sch_handle_egress net/core/dev.c:4545 [inline] __dev_queue_xmit+0x2185/0x2c00 net/core/dev.c:4808 packet_sendmsg+0x3dfa/0x5120 net/packet/af_packet.c:3114
The other tc actions and cls_bpf already use rcu_dereference_bh() here. Do the same.
--- net/sched/act_bpf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sched/act_bpf.c +1 -1
@@ -42,7 +42,7 @@ static int tcf_bpf_act(struct sk_buff *skb, const struct tc_action *act,tcf_lastuse_update (&prog->tcf_tm);bstats_update (this_cpu_ptr (prog->common.cpu_bstats), skb); - filter =rcu_dereference (prog->filter); + filter =rcu_dereference_bh (prog->filter);if (at_ingress) {__skb_push (skb, skb->mac_len); filter_res =bpf_prog_run_data_pointers (filter, skb);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 667/1067 gpio: timberdale: Return -ENOMEM on dynamic memory allocation in probe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vladimir Zapolskiy <[email protected]>
[ Upstream commit 8d7e62d5e9b2d2ff146f472a9215d7e29c7e2307 ]
Out of memory situation on driver's probe is expected to be reported to the driver's framework with a proper -ENOMEM error code.
--- drivers/gpio/gpio-timberdale.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpio/gpio-timberdale.c +1 -1
@@ -228,7 +228,7 @@ static int timbgpio_probe(struct platform_device *pdev) tgpio =devm_kzalloc (dev,sizeof (*tgpio),GFP_KERNEL );if (!tgpio) -return -EINVAL ; +return -ENOMEM ; tgpio->irq_base = pdata->irq_base;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 668/1067 pinctrl: meson: restore non-sleeping GPIO access
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Viacheslav Bocharov <[email protected]>
[ Upstream commit 9777530157e7b82fd994327ff878c4245dadc931 ]
Commit 28f240683871 ("pinctrl: meson: mark the GPIO controller as sleeping") set gpio_chip.can_sleep = true to work around gpio-shared-proxy holding a spinlock across a sleeping pinctrl config path. That locking bug is now fixed in the shared-proxy itself ("gpio:
shared-proxy: always serialize with a sleeping mutex"), so the controller-wide workaround is no longer needed; the meson GPIO controller does not sleep.
meson_gpio_get/set/direction_* access MMIO through regmap. The regmap_mmio bus uses fast I/O (spinlock) locking, so these value callbacks do not contain sleeping operations. Since gpio_chip.can_sleep describes the get/set value path, restore can_sleep = false.
Marking the controller sleeping also broke atomic value consumers such as w1-gpio (1-Wire bitbang): w1_io.c runs its read time slot under local_irq_save() and uses the non-cansleep gpiod_set_value() / gpiod_get_value(), which with can_sleep=true trigger WARN_ON(can_sleep) in gpiolib on every transferred bit (from w1_gpio_write_bit() / w1_gpio_read_bit() via w1_reset_bus() and w1_search()). The printk and stack dump inside the IRQs-off, microsecond-scale time slot destroy the bit timing, so reset/presence detection and ROM search fail: the bus master registers but w1_master_slave_count stays at 0 and no devices are found. Verified on an Amlogic A113X board (DS18B20 on GPIOA_14):
with can_sleep restored to false the warnings are gone and the sensor is detected and read again.
This must not be applied or backported without the shared-proxy locking fix above; otherwise the original Khadas VIM3 splat returns on boards that genuinely share a meson GPIO.
--- drivers/pinctrl/meson/pinctrl-meson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pinctrl/meson/pinctrl-meson.c +1 -1
@@ -619,7 +619,7 @@ static int meson_gpiolib_register(struct meson_pinctrl *pc) pc->chip.set = meson_gpio_set; pc->chip.base =-1 ; pc->chip.ngpio = pc->data->num_pins; - pc->chip.can_sleep = true; + pc->chip.can_sleep = false; ret =gpiochip_add_data (&pc->chip, pc);if (ret) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 669/1067 net/sched: hhf: clear heavy-hitter state on reset
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
[ Upstream commit a225f8c20712713406ae47024b8df42deacddd4a ]
HHF reset does not clear the classifier state used to identify heavy hitters. Packets after reset can therefore be scheduled using flow history from before the reset.
The reset operation should return the qdisc to an empty state.
Clear the heavy-hitter classifier tables when HHF is reset.
--- net/sched/sch_hhf.c | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+)
net/sched/sch_hhf.c +27 -0
@@ -461,12 +461,39 @@ static struct sk_buff *hhf_dequeue(struct Qdisc *sch)return skb; } +static void hhf_reset_classifier (struct hhf_sched_data *q) +{ +int i; + +if (!q->hh_flows) +return ; + +for (i =0 ; i <HH_FLOWS_CNT ; i++) { +struct hh_flow_state *flow, *next; +struct list_head *head = &q->hh_flows[i]; + +list_for_each_entry_safe (flow, next, head, flowchain) { +list_del (&flow->flowchain); +kfree (flow); + } + } +WRITE_ONCE (q->hh_flows_current_cnt,0 ); + +for (i =0 ; i <HHF_ARRAYS_CNT ; i++) { +if (q->hhf_valid_bits[i]) +bitmap_zero (q->hhf_valid_bits[i],HHF_ARRAYS_LEN ); + } + q->hhf_arrays_reset_timestamp =hhf_time_stamp (); +} +static void hhf_reset (struct Qdisc *sch) { +struct hhf_sched_data *q =qdisc_priv (sch);struct sk_buff *skb;while ((skb =hhf_dequeue (sch)) !=NULL )rtnl_kfree_skbs (skb, skb); +hhf_reset_classifier (q); }static void hhf_destroy (struct Qdisc *sch)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 670/1067 afs: Fix error code in afs_extract_vl_addrs()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 4897cb71d4ab1f7e1a214adb1e4b80176702368d ]
The error codes on these paths are only set on the first iteration through the loop. Set the correct error code on every iteration.
--- fs/afs/vl_list.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/afs/vl_list.c +3 -1
@@ -88,7 +88,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end, {struct afs_addr_list *alist;const u8 *b = *_b; -int ret = -EINVAL ; +int ret; alist =afs_alloc_addrlist (nr_addrs,VL_SERVICE , port);if (!alist)
@@ -106,6 +106,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,case DNS_ADDRESS_IS_IPV4 :if (end - b <4 ) {_leave (" = -EINVAL [short inet]" ); + ret = -EINVAL ; goto error; }memcpy (x, b,4 );
@@ -116,6 +117,7 @@ static struct afs_addr_list *afs_extract_vl_addrs(const u8 **_b, const u8 *end,case DNS_ADDRESS_IS_IPV6 :if (end - b <16 ) {_leave (" = -EINVAL [short inet6]" ); + ret = -EINVAL ; goto error; }memcpy (x, b,16 );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 671/1067 afs: use kvfree() to free memory allocated by kvcalloc()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zilin Guan <[email protected]>
[ Upstream commit cb39654926f8e7a08ecc1dcb3941628855275940 ]
op->more_files is allocated with kvcalloc() but released via afs_put_operation(), which uses kfree() internally. This mismach prevents the resource from being released properly and may lead to undefined behavior.
Fix this by using kvfree() to free op->more_files to match its allocation method.
--- fs/afs/fs_operation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/afs/fs_operation.c +1 -1
@@ -240,7 +240,7 @@ int afs_put_operation(struct afs_operation *op)for (i =0 ; i < op->nr_files -2 ; i++)if (op->more_files[i].put_vnode)iput (&op->more_files[i].vnode->netfs.inode); -kfree (op->more_files); +kvfree (op->more_files); }afs_end_cursor (&op->ac);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 672/1067 afs: Fix callback service message parsers to pass through -EAGAIN
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 0f36469d7ce98b362934113c550d08bb0c784231 ]
The AFS filesystem client uses an rxrpc server to listen for callback notifications. Each callback call type handler has a delivery function that parses the incoming request stream, and this should return -EAGAIN the last packet hasn't yet been seen, but all currently queued received data is consumed. afs_extract_data() does this, but the -EAGAIN return is switched to 0 inadvertantly
Fix callback service message parsers to pass through -EAGAIN
--- fs/afs/cmservice.c | 2 -- 1 file changed, 2 deletions(-)
fs/afs/cmservice.c +0 -2
@@ -388,7 +388,6 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *call) ret =afs_extract_data (call, false);switch (ret) {case 0 :break ; -case -EAGAIN :return 0 ;default :return ret; }
@@ -501,7 +500,6 @@ static int afs_deliver_cb_probe_uuid(struct afs_call *call) ret =afs_extract_data (call, false);switch (ret) {case 0 :break ; -case -EAGAIN :return 0 ;default :return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 673/1067 afs: Fix vllist leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit fc10c0ecf06f2981af5d04357612b00051e03e9e ]
Fix a leak of the new vllist in afs_update_cell() in the event that it is an empty list (nr_servers == 0), in which case the old list isn't displaced unless the old list is also empty.
--- fs/afs/cell.c | 2 ++ 1 file changed, 2 insertions(+)
fs/afs/cell.c +2 -0
@@ -474,6 +474,8 @@ static int afs_update_cell(struct afs_cell *cell)rcu_assign_pointer (cell->vl_servers, vllist); cell->dns_source = vllist->source; old = p; + }else { + old = vllist; }write_unlock (&cell->vl_servers_lock);afs_put_vlserverlist (cell->net, old);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 674/1067 afs: Fix the volume AFS_VOLUME_RM_TREE is set on
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 56b4e4b26f84411d880f968a539207b0a8889c8c ]
Fix afs_insert_volume_into_cell() to set AFS_VOLUME_RM_TREE on the volume replaced, not the new volume, as it's now removed from the cell's volume tree. This will cause the old volume to be removed from the tree twice and the new volume never to be removed.
--- fs/afs/volume.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/afs/volume.c +1 -1
@@ -37,7 +37,7 @@ static struct afs_volume *afs_insert_volume_into_cell(struct afs_cell *cell, goto found; } -set_bit (AFS_VOLUME_RM_TREE , &volume->flags); +set_bit (AFS_VOLUME_RM_TREE , &p->flags);rb_replace_node_rcu (&p->cell_node, &volume->cell_node, &cell->volumes); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 675/1067 afs: Fix unchecked-length string display in debug statement
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Howells <[email protected]>
[ Upstream commit 903d37c97228258da71e092f8b4ab260ce81497d ]
Fix afs_extract_vlserver_list() to limit the length of the displayed string in a debug statement().
--- fs/afs/vl_list.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
fs/afs/vl_list.c +5 -1
@@ -192,6 +192,8 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, b +=sizeof (*hdr);while (end - b >=sizeof (bs)) { +int nlen; + bs.name_len =afs_extract_le16 (&b); bs.priority =afs_extract_le16 (&b); bs.weight =afs_extract_le16 (&b);
@@ -201,10 +203,12 @@ struct afs_vlserver_list *afs_extract_vlserver_list(struct afs_cell *cell, bs.protocol = *b++; bs.nr_addrs = *b++; + nlen =min3 (bs.name_len, end - b,255 ); +_debug ("extract %u %u %u %u %u %u %*.*s" , bs.name_len, bs.priority, bs.weight, bs.port, bs.protocol, bs.nr_addrs, - bs.name_len, bs.name_len, b); + bs.name_len, nlen, b);if (end - b < bs.name_len)break ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 676/1067 ata: sata_gemini: unwind clocks on IDE pinctrl errors
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
[ Upstream commit c0ace4130e813acbabdfaa28d4e94a849c2ffdd7 ]
gemini_sata_bridge_init() prepares and enables both SATA PCLKs, then disables them again while keeping the clocks prepared for later bridge start and stop operations. If gemini_setup_ide_pins() fails after that, gemini_sata_probe() returns directly and skips the existing out_unprep_clk unwind path.
Route the IDE pinctrl failure through out_unprep_clk so the clocks prepared by gemini_sata_bridge_init() are unprepared before probe fails.
--- drivers/ata/sata_gemini.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/ata/sata_gemini.c +1 -1
@@ -386,7 +386,7 @@ static int gemini_sata_probe(struct platform_device *pdev)if (sg->ide_pins) { ret =gemini_setup_ide_pins (dev);if (ret) -return ret; + goto out_unprep_clk; }dev_info (dev,"set up the Gemini IDE/SATA nexus\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 677/1067 HID: picolcd: prevent NULL pointer dereference in picolcd_send_and_wait()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Georgiy Osokin <[email protected]>
[ Upstream commit 0021eb09041f021c079be1022934a280f7f176c0 ]
In picolcd_send_and_wait(), an integer overflow of the signed loop counter 'k' can theoretically lead to a NULL pointer dereference of 'raw_data'. If the loop executes more than INT_MAX times, 'k' becomes negative, making the condition 'k < size' true even when 'size' is 0.
Change the type of 'k' to 'unsigned int' to prevent the overflow and eliminate the out-of-bounds access.
Found by Linux Verification Center (linuxtesting.org) with the Svace static analysis tool.
--- drivers/hid/hid-picolcd_core.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/hid/hid-picolcd_core.c +2 -1
@@ -72,7 +72,8 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,struct picolcd_pending *work;struct hid_report *report =picolcd_out_report (report_id, hdev);unsigned long flags; -int i, j, k; +int i, j; +unsigned int k;if (!report || !data)return NULL ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 678/1067 HID: core: Fix OOB read in hid_get_report for numbered reports
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lee Jones <[email protected]>
[ Upstream commit af1a9b65ebe8a948eda805c14b78d4d0767cb1b5 ]
When a caller passes a size of 0 to hid_report_raw_event() for a numbered report, the function originally called hid_get_report() before performing any size validation.
Inside hid_get_report(), if the report is numbered (report_enum->numbered is true), it unconditionally dereferences data[0] to extract the report ID. With a size of 0, this results in an out-of-bounds read or kernel panic.
Fix this by moving the numbered report size validation check before the call to hid_get_report(), ensuring that size is at least 1 before dereferencing the data pointer.
--- drivers/hid/hid-core.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/hid/hid-core.c +7 -0
@@ -2001,6 +2001,13 @@ int hid_report_raw_event(struct hid_device *hid, enum hid_report_type type, u8 *u8 *cdata = data;int ret =0 ; +if (report_enum->numbered && (size <1 || bufsize <1 )) { +hid_warn_ratelimited (hid, +"Event data for numbered report is too short (%d vs %zu)\n" , + size, bufsize); +return -EINVAL ; + } + report =hid_get_report (report_enum, data);if (!report)return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 679/1067 arm64/mm: convert ptep_clear() to ptep_get_and_clear()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ryan Roberts <[email protected]>
[ Upstream commit cbb0294fdd72a5f63ec59fad5c0a98d63bd572fc ]
ptep_clear() is a generic wrapper around the arch-implemented ptep_get_and_clear(). We are about to convert ptep_get_and_clear() into a public version and private version (__ptep_get_and_clear()) to support the transparent contpte work. We won't have a private version of ptep_clear() so let's convert it to directly call ptep_get_and_clear().
Stable-dep-of: ff4c5a0de1f2 ("arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()")
--- arch/arm64/mm/hugetlbpage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/arm64/mm/hugetlbpage.c +1 -1
@@ -236,7 +236,7 @@ static void clear_flush(struct mm_struct *mm,unsigned long i, saddr = addr;for (i =0 ; i < ncontig; i++, addr += pgsize, ptep++) -ptep_clear (mm, addr, ptep); +ptep_get_and_clear (mm, addr, ptep);flush_tlb_range (&vma, saddr, addr); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 680/1067 arm64/mm: Optimize TLB flush in unmap_hotplug_[pmd|pud]_range()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Anshuman Khandual <[email protected]>
[ Upstream commit ff4c5a0de1f2ef7737a8688a86e19301e567020d ]
Commit 48478b9f7913 ("arm64/mm: Enable batched TLB flush in unmap_hotplug_range") inadvertently introduced redundant TLB invalidation when clearing a block entry, resulting in unnecessary broadcast invalidation on CPUs without support for range-based invalidation.
Re-introduce the old behaviour, along with some expanded comments to help people working in this area next time around.
--- arch/arm64/mm/mmu.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-)
arch/arm64/mm/mmu.c +9 -2
@@ -956,7 +956,13 @@ static void unmap_hotplug_pmd_range(pud_t *pudp, unsigned long addr,if (free_mapped) {/* CONT blocks are not supported in the vmemmap */ WARN_ON (pmd_cont (pmd)); -flush_tlb_kernel_range (addr, addr +PMD_SIZE ); +/* +* Invalidating a block entry requires just +* a single overlapping TLB invalidation, +* so limit the range of the flush to a single +* page. +*/ +flush_tlb_kernel_range (addr, addr +PAGE_SIZE );free_hotplug_page_range (pmd_page (pmd),PMD_SIZE , altmap); }
@@ -986,7 +992,8 @@ static void unmap_hotplug_pud_range(p4d_t *p4dp, unsigned long addr,if (pud_sect (pud)) {pud_clear (pudp);if (free_mapped) { -flush_tlb_kernel_range (addr, addr +PUD_SIZE ); +/* See comment in unmap_hotplug_pmd_range(). */ +flush_tlb_kernel_range (addr, addr +PAGE_SIZE );free_hotplug_page_range (pud_page (pud),PUD_SIZE , altmap); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 681/1067 net: usb: net1080: validate packet_len before pad-byte access in rx_fixup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 03f384bc0cb8d4a1301d4f5b0baef2d980258383 ]
For an even packet_len, net1080_rx_fixup() reads the pad byte at skb->data[packet_len] before the skb->len != packet_len check further down, and packet_len is only bounded against NC_MAX_PACKET. A malicious NetChip 1080 device can send a short frame advertising a large even packet_len (e.g. 0x4000), so the pad-byte read lands past the end of the skb:
BUG: KASAN: slab-out-of-bounds in net1080_rx_fixup Read of size 1 at addr ffff8880106c83c6 by task ksoftirqd/0/14 ... net1080_rx_fixup (drivers/net/usb/net1080.c:384) usbnet_bh (drivers/net/usb/usbnet.c:1589) process_one_work (kernel/workqueue.c:3322) bh_worker (kernel/workqueue.c:3708) tasklet_action (kernel/softirq.c:965) handle_softirqs (kernel/softirq.c:622) ...
Reject the frame when packet_len >= skb->len before reading.
--- drivers/net/usb/net1080.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/net/usb/net1080.c +1 -1
@@ -381,7 +381,7 @@ static int net1080_rx_fixup(struct usbnet *dev, struct sk_buff *skb)skb_trim (skb, skb->len -sizeof *trailer);if ((packet_len &0x01 ) ==0 ) { -if (skb->data [packet_len] !=PAD_BYTE ) { +if (packet_len >= skb->len || skb->data[packet_len] !=PAD_BYTE ) { dev->net->stats.rx_frame_errors++;netdev_dbg (dev->net,"bad pad\n" );return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 682/1067 gue: validate REMCSUM private option length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Qihang <[email protected]>
[ Upstream commit d335dcc6f521571d57117b8deeebc940836e5450 ]
GUE private flags can indicate that remote checksum offload metadata is present. The private flags field itself is accounted for by guehdr_flags_len(), but guehdr_priv_flags_len() currently returns 0 even when GUE_PFLAG_REMCSUM is set.
This lets a packet with only the private flags field pass validate_gue_flags(), after which gue_remcsum() and gue_gro_remcsum() read the missing REMCSUM start/offset fields from the following bytes.
Account for GUE_PLEN_REMCSUM when GUE_PFLAG_REMCSUM is present so that malformed packets are rejected during option validation.
--- include/net/gue.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
include/net/gue.h +1 -1
@@ -80,7 +80,7 @@ static inline size_t guehdr_flags_len(__be16 flags)static inline size_t guehdr_priv_flags_len (__be32 flags) { -return 0 ; +return (flags &GUE_PFLAG_REMCSUM ) ?GUE_PLEN_REMCSUM :0 ; }/* Validate standard and private flags. Returns non-zero (meaning invalid)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 683/1067 netfilter: xt_u32: reject invalid shift counts
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
[ Upstream commit 64cdf7d30ac18e43df6c48004435febb965809a8 ]
u32_match_it() executes rule-supplied shift operands on a 32-bit value. A malformed u32 rule can provide a shift count of 32 or more, triggering an undefined shift out-of-bounds during packet evaluation.
Validate XT_U32_LEFTSH and XT_U32_RIGHTSH operands in u32_mt_checkentry() and reject malformed rules before they reach the packet path.
--- net/netfilter/xt_u32.c | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-)
net/netfilter/xt_u32.c +11 -1
@@ -100,7 +100,7 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par) {const struct xt_u32 *data = par->matchinfo;const struct xt_u32_test *ct; -unsigned int i; +unsigned int i, j;if (data->ntests >ARRAY_SIZE (data->tests))return -EINVAL ;
@@ -111,6 +111,16 @@ static int u32_mt_checkentry(const struct xt_mtchk_param *par)if (ct->nnums >ARRAY_SIZE (ct->location) || ct->nvalues >ARRAY_SIZE (ct->value))return -EINVAL ; + +for (j =1 ; j < ct->nnums; ++j) { +switch (ct->location[j].nextop) { +case XT_U32_LEFTSH : +case XT_U32_RIGHTSH : +if (ct->location[j].number >=32 ) +return -EINVAL ; +break ; + } + } }return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 684/1067 netfilter: xt_rateest: fix u64 truncation in xt_rateest_mt()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Wu <[email protected]>
[ Upstream commit 444853cd438201007da5359821adcc2995655ab1 ]
On links faster than ~34 Gbps, where byte rate may exceed 2^32-1 (~ 4.3 GBps), the comparison result becomes incorrect because the truncated value no longer reflects the actual estimator rate.
Fix by changing the local variables to u64.
--- net/netfilter/xt_rateest.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/xt_rateest.c +1 -1
@@ -16,7 +16,7 @@ xt_rateest_mt(const struct sk_buff *skb, struct xt_action_param *par) {const struct xt_rateest_match_info *info = par->matchinfo;struct gnet_stats_rate_est64 sample = {0 }; -u_int32_t bps1, bps2, pps1, pps2; +u64 bps1, bps2, pps1, pps2;bool ret = true;gen_estimator_read (&info->est1->rate_est, &sample);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 685/1067 netfilter: ip6tables: mark malformed IPv6 extension headers for hotdrop
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhixing Chen <[email protected]>
[ Upstream commit 43ccc20b5a733226417832cf16ef45322e594990 ]
The ah, hbh and rt matches check that the fixed extension header is present, then use the header length field to derive the advertised extension header length for matching.
For the ah match, add the missing advertised-length check. For hbh and rt, update the existing advertised-length checks. In all three cases, set hotdrop to true before returning false when the advertised extension header length exceeds the available skb data.
Returning false treats the packet as a rule mismatch. Set hotdrop to true and drop malformed packets so they cannot bypass rules intended to drop packets with these IPv6 extension headers.
--- net/ipv6/netfilter/ip6t_ah.c | 5 +++++ net/ipv6/netfilter/ip6t_hbh.c | 1 + net/ipv6/netfilter/ip6t_rt.c | 3 ++- 3 files changed, 8 insertions(+), 1 deletion(-)
net/ipv6/netfilter/ip6t_ah.c +5 -0
@@ -56,6 +56,11 @@ static bool ah_mt6(const struct sk_buff *skb, struct xt_action_param *par) } hdrlen =ipv6_authlen (ah); +if (skb->len - ptr < hdrlen) { +/* Packet smaller than its length field */ + par->hotdrop = true; +return false; + }pr_debug ("IPv6 AH LEN %u %u " , hdrlen, ah->hdrlen);pr_debug ("RES %04X " , ah->reserved);
net/ipv6/netfilter/ip6t_hbh.c +1 -0
@@ -75,6 +75,7 @@ hbh_mt6(const struct sk_buff *skb, struct xt_action_param *par) hdrlen =ipv6_optlen (oh);if (skb->len - ptr < hdrlen) {/* Packet smaller than it's length field */ + par->hotdrop = true;return false; }
net/ipv6/netfilter/ip6t_rt.c +2 -1
@@ -56,7 +56,8 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par) hdrlen =ipv6_optlen (rh);if (skb->len - ptr < hdrlen) { -/* Pcket smaller than its length field */ +/* Packet smaller than its length field */ + par->hotdrop = true;return false; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 686/1067 netfilter: xt_connmark: reject invalid shift parameters
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
[ Upstream commit 1b47026fb4b35bac850ad6e8a4ad7fc018e09ebc ]
Revision 2 of the CONNMARK target accepts user-controlled shift parameters and applies them to 32-bit mark values in connmark_tg_shift().
A shift_bits value of 32 or more triggers an undefined-shift bug when the rule is evaluated. Invalid shift_dir values are also accepted and silently fall back to the left-shift path.
Reject invalid revision-2 shift parameters in connmark_tg_check() so malformed rules fail at installation time, before they can reach the packet path.
--- net/netfilter/xt_connmark.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
net/netfilter/xt_connmark.c +12 -2
@@ -112,6 +112,16 @@ static int connmark_tg_check(const struct xt_tgchk_param *par)return ret; } +static int connmark_tg_check_v2 (const struct xt_tgchk_param *par) +{ +const struct xt_connmark_tginfo2 *info = par->targinfo; + +if (info->shift_dir >D_SHIFT_RIGHT || info->shift_bits >=32 ) +return -EINVAL ; + +return connmark_tg_check (par); +} +static void connmark_tg_destroy (const struct xt_tgdtor_param *par) {nf_ct_netns_put (par->net, par->family);
@@ -162,7 +172,7 @@ static struct xt_target connmark_tg_reg[] __read_mostly = { .name = "CONNMARK", .revision = 2, .family = NFPROTO_IPV4, - .checkentry = connmark_tg_check, + .checkentry = connmark_tg_check_v2, .target = connmark_tg_v2, .targetsize = sizeof(struct xt_connmark_tginfo2), .destroy = connmark_tg_destroy,
@@ -183,7 +193,7 @@ static struct xt_target connmark_tg_reg[] __read_mostly = { .name = "CONNMARK", .revision = 2, .family = NFPROTO_IPV6, - .checkentry = connmark_tg_check, + .checkentry = connmark_tg_check_v2, .target = connmark_tg_v2, .targetsize = sizeof(struct xt_connmark_tginfo2), .destroy = connmark_tg_destroy,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 687/1067 net/mlx5e: Fix HV VHCA stats zero-sized buffer allocation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Liu <[email protected]>
[ Upstream commit 25f6b929c7e379cbea7cb8caa67b49b2d1efae17 ]
mlx5e_hv_vhca_stats_create() is called from mlx5e_nic_enable(), before mlx5e_open(). At that point priv->stats_nch is still zero, because it is only ever incremented in mlx5e_channel_stats_alloc(), which is reached only from mlx5e_open_channel().
mlx5e_hv_vhca_stats_buf_size() therefore returns 0, and kvzalloc(0, GFP_KERNEL) returns ZERO_SIZE_PTR ((void *)16) rather than NULL. The "if (!buf)" guard does not catch this, and mlx5e_hv_vhca_stats_create() completes "successfully" with priv->stats_agent.buf set to ZERO_SIZE_PTR.
Once channels are opened (priv->stats_nch > 0) and the hypervisor enables stats reporting, mlx5e_hv_vhca_stats_work() recomputes buf_len using the new non-zero stats_nch and calls memset(buf, 0, buf_len) on ZERO_SIZE_PTR, faulting at address 0x10.
Allocate the buffer based on priv->max_nch, which is set in mlx5e_priv_init() and is the upper bound on stats_nch:
- Add a separate helper mlx5e_hv_vhca_stats_buf_max_size() that returns sizeof(per_ring_stats) * max(max_nch, stats_nch), and use it for the kvzalloc() in mlx5e_hv_vhca_stats_create().
- Keep mlx5e_hv_vhca_stats_buf_size() (which returns based on stats_nch) for the worker's active payload size, so the wire format (block->rings = stats_nch) and the amount of data filled by mlx5e_hv_vhca_fill_stats() are unchanged.
The max(max_nch, stats_nch) guard handles the rare case where mlx5e_attach_netdev() recomputes max_nch downward across a detach/resume cycle while priv->stats_nch persists (mlx5e_detach_netdev does not call mlx5e_priv_cleanup, so stats_nch is only reset when the netdev is destroyed). Without the guard, the worker could compute buf_len from stats_nch and overrun the smaller buffer allocated based on the reduced max_nch.
Allocating a non-zero buffer also makes the kvzalloc() failure path in mlx5e_hv_vhca_stats_create() reachable for the first time: it returns early without (re)creating the agent. Clear priv->stats_agent.{agent,buf} in mlx5e_hv_vhca_stats_destroy() after freeing them, so that if a later create() bails out on this path, a subsequent teardown does not double-free the stale agent/buffer left from a previous enable/disable cycle.
This mirrors the existing mlx5e pattern of preallocating arrays of size max_nch (e.g. priv->channel_stats) and lazily populating entries up to stats_nch on demand.
--- .../net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c +9 -1
@@ -54,6 +54,12 @@ static int mlx5e_hv_vhca_stats_buf_size(struct mlx5e_priv *priv) priv->stats_nch); } +static int mlx5e_hv_vhca_stats_buf_max_size (struct mlx5e_priv *priv) +{ +return (sizeof (struct mlx5e_hv_vhca_per_ring_stats ) * +max (priv->max_nch, priv->stats_nch)); +} +static void mlx5e_hv_vhca_stats_work (struct work_struct *work) {struct mlx5e_hv_vhca_stats_agent *sagent;
@@ -122,7 +128,7 @@ static void mlx5e_hv_vhca_stats_cleanup(struct mlx5_hv_vhca_agent *agent)void mlx5e_hv_vhca_stats_create (struct mlx5e_priv *priv) { -int buf_len =mlx5e_hv_vhca_stats_buf_size (priv); +int buf_len =mlx5e_hv_vhca_stats_buf_max_size (priv);struct mlx5_hv_vhca_agent *agent; priv->stats_agent.buf =kvzalloc (buf_len,GFP_KERNEL );
@@ -155,5 +161,7 @@ void mlx5e_hv_vhca_stats_destroy(struct mlx5e_priv *priv)return ;mlx5_hv_vhca_agent_destroy (priv->stats_agent.agent); + priv->stats_agent.agent =NULL ;kvfree (priv->stats_agent.buf); + priv->stats_agent.buf =NULL ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 688/1067 net/mlx5e: Fix HV VHCA stats agent registration race
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Feng Liu <[email protected]>
[ Upstream commit 89b25b5f46f488ea3b29b3444864c76944c9075b ]
mlx5e_hv_vhca_stats_create() registers the stats agent through mlx5_hv_vhca_agent_create(). The helper publishes the agent in hv_vhca->agents[type] under agents_lock and immediately schedules an asynchronous control invalidation on the HV VHCA workqueue before returning to mlx5e.
The asynchronous invalidation invokes the control agent's invalidate callback, which reads the hypervisor control block and forwards the command to mlx5e_hv_vhca_stats_control(). That callback may either:
- call cancel_delayed_work_sync(&priv->stats_agent.work), or
- call queue_delayed_work(priv->wq, &sagent->work, sagent->delay).
However, the delayed_work and priv->stats_agent.agent are only initialized after mlx5_hv_vhca_agent_create() returns to mlx5e:
agent = mlx5_hv_vhca_agent_create(...); /* publish + invalidate */
...
priv->stats_agent.agent = agent; /* too late */
INIT_DELAYED_WORK(&priv->stats_agent.work, ...); /* too late */If the asynchronous control path runs before the two assignments above, it can:
- Operate on an uninitialized delayed_work whose timer.function is NULL. queue_delayed_work() calls add_timer() unconditionally, so when the timer expires the timer softirq invokes a NULL function pointer.
- Re-initialize the timer later through INIT_DELAYED_WORK() while the timer is already enqueued in the timer wheel, corrupting the hlist (entry.pprev cleared while the previous bucket node still points at this entry).
- When the worker eventually runs, mlx5e_hv_vhca_stats_work() reads
sagent->agent (NULL) and dereferences it inside
mlx5_hv_vhca_agent_write().Fix this by:
- Initializing priv->stats_agent.work before invoking mlx5_hv_vhca_agent_create(), so the work is always in a valid state when the control callback observes it.
- Adding a struct mlx5_hv_vhca_agent **ctx_update out-parameter to mlx5_hv_vhca_agent_create(). The helper writes the agent pointer to *ctx_update before publishing into hv_vhca->agents[] and triggering the agents_update flow, so any callback subsequently invoked from that flow already sees a valid priv->stats_agent.agent. This avoids having the control callback participate in agent initialization.
While at it, access priv->stats_agent.agent with READ_ONCE()/WRITE_ONCE() for the cross-CPU access with the worker, and clear priv->stats_agent.buf on the agent_create() failure path.
--- .../mellanox/mlx5/core/en/hv_vhca_stats.c | 21 +++++++++++-------- .../ethernet/mellanox/mlx5/core/lib/hv_vhca.c | 8 +++++-- .../ethernet/mellanox/mlx5/core/lib/hv_vhca.h | 6 ++++-- 3 files changed, 22 insertions(+), 13 deletions(-)
drivers/net/ethernet/mellanox/mlx5/core/en/hv_vhca_stats.c +12 -9
@@ -73,7 +73,7 @@ static void mlx5e_hv_vhca_stats_work(struct work_struct *work) sagent = container_of(dwork, struct mlx5e_hv_vhca_stats_agent, work); priv = container_of(sagent, struct mlx5e_priv, stats_agent); buf_len =mlx5e_hv_vhca_stats_buf_size (priv); - agent = sagent->agent; + agent =READ_ONCE (sagent->agent); buf = sagent->buf;memset (buf,0 , buf_len);
@@ -135,11 +135,14 @@ void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv)if (!priv->stats_agent.buf)return ; +INIT_DELAYED_WORK (&priv->stats_agent.work, mlx5e_hv_vhca_stats_work); + agent =mlx5_hv_vhca_agent_create (priv->mdev->hv_vhca,MLX5_HV_VHCA_AGENT_STATS , mlx5e_hv_vhca_stats_control,NULL , mlx5e_hv_vhca_stats_cleanup, - priv); + priv, + &priv->stats_agent.agent);if (IS_ERR_OR_NULL (agent)) {if (IS_ERR (agent))
@@ -148,20 +151,20 @@ void mlx5e_hv_vhca_stats_create(struct mlx5e_priv *priv) PTR_ERR(agent));kvfree (priv->stats_agent.buf); -return ; + priv->stats_agent.buf =NULL ; } - - priv->stats_agent.agent = agent; -INIT_DELAYED_WORK (&priv->stats_agent.work, mlx5e_hv_vhca_stats_work); }void mlx5e_hv_vhca_stats_destroy (struct mlx5e_priv *priv) { -if (IS_ERR_OR_NULL (priv->stats_agent.agent)) +struct mlx5_hv_vhca_agent *agent; + + agent =READ_ONCE (priv->stats_agent.agent); +if (IS_ERR_OR_NULL (agent))return ; -mlx5_hv_vhca_agent_destroy (priv->stats_agent.agent); - priv->stats_agent.agent =NULL ; +mlx5_hv_vhca_agent_destroy (agent); +WRITE_ONCE (priv->stats_agent.agent,NULL );kvfree (priv->stats_agent.buf); priv->stats_agent.buf =NULL ; }
drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.c +6 -2
@@ -190,7 +190,7 @@ mlx5_hv_vhca_control_agent_create(struct mlx5_hv_vhca *hv_vhca)return mlx5_hv_vhca_agent_create (hv_vhca,MLX5_HV_VHCA_AGENT_CONTROL ,NULL , mlx5_hv_vhca_control_agent_invalidate, -NULL ,NULL ); +NULL ,NULL ,NULL ); }static void mlx5_hv_vhca_control_agent_destroy (struct mlx5_hv_vhca_agent *agent)
@@ -256,7 +256,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca,void (*invalidate)(struct mlx5_hv_vhca_agent *,u64 block_mask), void (*cleaup)(struct mlx5_hv_vhca_agent *agent), - void *priv) + void *priv, + struct mlx5_hv_vhca_agent **ctx_update) { struct mlx5_hv_vhca_agent *agent;
@@ -284,6 +285,9 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca, agent->invalidate = invalidate; agent->cleanup = cleaup; +if (ctx_update) +WRITE_ONCE (*ctx_update, agent); +mutex_lock (&hv_vhca->agents_lock); hv_vhca->agents[type] = agent;mutex_unlock (&hv_vhca->agents_lock);
drivers/net/ethernet/mellanox/mlx5/core/lib/hv_vhca.h +4 -2
@@ -43,7 +43,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca,void (*invalidate)(struct mlx5_hv_vhca_agent *,u64 block_mask), void (*cleanup)(struct mlx5_hv_vhca_agent *agent), - void *context); + void *context, + struct mlx5_hv_vhca_agent **ctx_update);void mlx5_hv_vhca_agent_destroy (struct mlx5_hv_vhca_agent *agent); int mlx5_hv_vhca_agent_write(struct mlx5_hv_vhca_agent *agent,
@@ -84,7 +85,8 @@ mlx5_hv_vhca_agent_create(struct mlx5_hv_vhca *hv_vhca,void (*invalidate)(struct mlx5_hv_vhca_agent *,u64 block_mask), void (*cleanup)(struct mlx5_hv_vhca_agent *agent), - void *context) + void *context, + struct mlx5_hv_vhca_agent **ctx_update) { return NULL; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 689/1067 qede: fix off-by-one in BD ring consumption on build_skb failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shigeru Yoshida <[email protected]>
[ Upstream commit a0a558ca7e75b49e71f8c545c30e8c005e6e4e2f ]
qede_rx_build_skb() and qede_tpa_rx_build_skb() do not check for a NULL return from qede_build_skb(). When it returns NULL under memory pressure, the functions still consume a BD from the ring before returning NULL. The callers then recycle additional BDs, resulting in one extra BD being consumed (off-by-one). This desynchronizes the BD ring, which can corrupt DMA page reference counts and lead to SLUB freelist corruption.
Commit 4e910dbe3650 ("qede: confirm skb is allocated before using") added a NULL check inside qede_build_skb() to prevent a NULL pointer dereference, but did not address the missing NULL checks in the callers, making this off-by-one reachable.
Fix this by adding NULL checks for the return value of qede_build_skb() in both qede_rx_build_skb() and qede_tpa_rx_build_skb(), returning NULL immediately before any BD ring manipulation.
--- drivers/net/ethernet/qlogic/qede/qede_fp.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/net/ethernet/qlogic/qede/qede_fp.c +5 -0
@@ -765,6 +765,9 @@ qede_tpa_rx_build_skb(struct qede_dev *edev,struct sk_buff *skb; skb =qede_build_skb (rxq, bd, len, pad); +if (unlikely (!skb)) +return NULL ; + bd->page_offset += rxq->rx_buf_seg_size;if (bd->page_offset ==PAGE_SIZE ) {
@@ -812,6 +815,8 @@ qede_rx_build_skb(struct qede_dev *edev, } skb =qede_build_skb (rxq, bd, len, pad); +if (unlikely (!skb)) +return NULL ;if (unlikely (qede_realloc_rx_buffer (rxq, bd))) {/* Incr page ref count to reuse on allocation failure so
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 690/1067 net: qualcomm: rmnet: add tx packets aggregation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Daniele Palmas <[email protected]>
[ Upstream commit 64b5d1f8f2d1b3f039cfb0dd8035892015543e58 ]
Add tx packets aggregation.
Bidirectional TCP throughput tests through iperf with low-cat Thread-x based modems revelead performance issues both in tx and rx.
The Windows driver does not show this issue: inspecting USB packets revealed that the only notable change is the driver enabling tx packets aggregation.
Tx packets aggregation is by default disabled and can be enabled by increasing the value of ETHTOOL_A_COALESCE_TX_MAX_AGGR_FRAMES.
The maximum aggregated size is by default set to a reasonably low value in order to support the majority of modems.
This implementation is based on patches available in Code Aurora repositories (msm kernel) whose main authors are
Subash Abhinov Kasiviswanathan <[email protected]> Sean Tranchetti <[email protected]>
Stable-dep-of: f0f1887a9e30 ("net: qualcomm: rmnet: validate MAP frame length before ingress parsing")
--- .../ethernet/qualcomm/rmnet/rmnet_config.c | 5 + .../ethernet/qualcomm/rmnet/rmnet_config.h | 20 ++ .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 18 +- .../net/ethernet/qualcomm/rmnet/rmnet_map.h | 6 + .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 191 ++++++++++++++++++ .../net/ethernet/qualcomm/rmnet/rmnet_vnd.c | 9 +- .../net/ethernet/qualcomm/rmnet/rmnet_vnd.h | 1 + 7 files changed, 246 insertions(+), 4 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.c +5 -0
@@ -12,6 +12,7 @@#include "rmnet_handlers.h" #include "rmnet_vnd.h" #include "rmnet_private.h" +#include "rmnet_map.h" /* Local Definitions and Declarations */
@@ -39,6 +40,8 @@ static int rmnet_unregister_real_device(struct net_device *real_dev)if (port->nr_rmnet_devs)return -EINVAL ; +rmnet_map_tx_aggregate_exit (port); +netdev_rx_handler_unregister (real_dev);kfree (port);
@@ -79,6 +82,8 @@ static int rmnet_register_real_device(struct net_device *real_dev,for (entry =0 ; entry <RMNET_MAX_LOGICAL_EP ; entry++)INIT_HLIST_HEAD (&port->muxed_ep[entry]); +rmnet_map_tx_aggregate_init (port); +netdev_dbg (real_dev,"registered with rmnet\n" );return 0 ; }
drivers/net/ethernet/qualcomm/rmnet/rmnet_config.h +20 -0
@@ -6,6 +6,7 @@*/ #include <linux/skbuff.h> +#include <linux/time.h> #include <net/gro_cells.h> #ifndef _RMNET_CONFIG_H_
@@ -20,6 +21,12 @@ struct rmnet_endpoint {struct rcu_head rcu; }; +struct rmnet_egress_agg_params { +u32 bytes; +u32 count; +u64 time_nsec; +}; +/* One instance of this structure is instantiated for each real_dev associated * with rmnet. */
@@ -31,6 +38,19 @@ struct rmnet_port {struct hlist_head muxed_ep[RMNET_MAX_LOGICAL_EP ];struct net_device *bridge_ep;struct net_device *rmnet_dev; + +/* Egress aggregation information */ +struct rmnet_egress_agg_params egress_agg_params; +/* Protect aggregation related elements */ +spinlock_t agg_lock; +struct sk_buff *skbagg_head; +struct sk_buff *skbagg_tail; +int agg_state; +u8 agg_count; +struct timespec64 agg_time; +struct timespec64 agg_last; +struct hrtimer hrtimer; +struct work_struct agg_wq; };extern struct rtnl_link_ops rmnet_link_ops;
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +16 -2
@@ -164,8 +164,18 @@ static int rmnet_map_egress_handler(struct sk_buff *skb, map_header->mux_id = mux_id; - skb->protocol =htons (ETH_P_MAP ); +if (READ_ONCE (port->egress_agg_params.count) >1 ) { +unsigned int len; + + len =rmnet_map_tx_aggregate (skb, port, orig_dev); +if (likely (len)) { +rmnet_vnd_tx_fixup_len (len, orig_dev); +return -EINPROGRESS ; + } +return -ENOMEM ; + } + skb->protocol =htons (ETH_P_MAP );return 0 ; }
@@ -235,6 +245,7 @@ void rmnet_egress_handler(struct sk_buff *skb)struct rmnet_port *port;struct rmnet_priv *priv;u8 mux_id; +int err;sk_pacing_shift_update (skb->sk,8 );
@@ -247,8 +258,11 @@ void rmnet_egress_handler(struct sk_buff *skb)if (!port) goto drop; -if (rmnet_map_egress_handler (skb, port, mux_id, orig_dev)) + err =rmnet_map_egress_handler (skb, port, mux_id, orig_dev); +if (err == -ENOMEM ) goto drop; +else if (err == -EINPROGRESS ) +return ;rmnet_vnd_tx_fixup (skb, orig_dev);
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +6 -0
@@ -53,5 +53,11 @@ void rmnet_map_checksum_uplink_packet(struct sk_buff *skb,struct net_device *orig_dev, int csum_type);int rmnet_map_process_next_hdr_packet (struct sk_buff *skb,u16 len); +unsigned int rmnet_map_tx_aggregate (struct sk_buff *skb,struct rmnet_port *port, +struct net_device *orig_dev); +void rmnet_map_tx_aggregate_init (struct rmnet_port *port); +void rmnet_map_tx_aggregate_exit (struct rmnet_port *port); +void rmnet_map_update_ul_agg_config (struct rmnet_port *port,u32 size, +u32 count,u32 time);#endif /* _RMNET_MAP_H_ */
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +191 -0
200 lines not on this page · raw message
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.c +7 -2
@@ -29,7 +29,7 @@ void rmnet_vnd_rx_fixup(struct sk_buff *skb, struct net_device *dev)u64_stats_update_end (&pcpu_ptr->syncp); } -void rmnet_vnd_tx_fixup (struct sk_buff *skb,struct net_device *dev) +void rmnet_vnd_tx_fixup_len (unsigned int len,struct net_device *dev) {struct rmnet_priv *priv =netdev_priv (dev);struct rmnet_pcpu_stats *pcpu_ptr;
@@ -38,10 +38,15 @@ void rmnet_vnd_tx_fixup(struct sk_buff *skb, struct net_device *dev)u64_stats_update_begin (&pcpu_ptr->syncp); pcpu_ptr->stats.tx_pkts++; - pcpu_ptr->stats.tx_bytes += skb->len; + pcpu_ptr->stats.tx_bytes += len;u64_stats_update_end (&pcpu_ptr->syncp); } +void rmnet_vnd_tx_fixup (struct sk_buff *skb,struct net_device *dev) +{ +rmnet_vnd_tx_fixup_len (skb->len, dev); +} +/* Network Device Operations */ static netdev_tx_t rmnet_vnd_start_xmit(struct sk_buff *skb,
drivers/net/ethernet/qualcomm/rmnet/rmnet_vnd.h +1 -0
@@ -16,6 +16,7 @@ int rmnet_vnd_newlink(u8 id, struct net_device *rmnet_dev,int rmnet_vnd_dellink (u8 id,struct rmnet_port *port,struct rmnet_endpoint *ep);void rmnet_vnd_rx_fixup (struct sk_buff *skb,struct net_device *dev); +void rmnet_vnd_tx_fixup_len (unsigned int len,struct net_device *dev);void rmnet_vnd_tx_fixup (struct sk_buff *skb,struct net_device *dev);void rmnet_vnd_setup (struct net_device *dev);int rmnet_vnd_validate_real_dev_mtu (struct net_device *real_dev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 691/1067 net: qualcomm: rmnet: validate MAP frame length before ingress parsing
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit f0f1887a9e30712a1df03e152dce6fb91344b1f3 ]
When ingress deaggregation is disabled, rmnet_map_ingress_handler() passes the skb straight to __rmnet_map_ingress_handler(), skipping the length validation that rmnet_map_deaggregate() performs on the aggregated path. The parser then dereferences the MAP header and csum header/trailer based on the on-wire pkt_len without checking skb->len, so a short frame is read out of bounds:
BUG: KASAN: slab-out-of-bounds in rmnet_map_checksum_downlink_packet Read of size 1 at addr ffff88801118ed00 by task exploit/147 Call Trace: ... rmnet_map_checksum_downlink_packet (drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c:413) __rmnet_map_ingress_handler (drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:96) rmnet_rx_handler (drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c:129) __netif_receive_skb_core.constprop.0 (net/core/dev.c:6089) netif_receive_skb (net/core/dev.c:6460) tun_get_user (drivers/net/tun.c:1955) tun_chr_write_iter (drivers/net/tun.c:2001) vfs_write (fs/read_write.c:688) ksys_write (fs/read_write.c:740) do_syscall_64 (arch/x86/entry/syscall_64.c:94) ...
Factor that validation out of rmnet_map_deaggregate() into rmnet_map_validate_packet_len() and run it on the no-aggregation path too. The MAP header is bounds-checked first, since this path can receive a frame shorter than the header.
--- .../ethernet/qualcomm/rmnet/rmnet_handlers.c | 5 +- .../net/ethernet/qualcomm/rmnet/rmnet_map.h | 1 + .../ethernet/qualcomm/rmnet/rmnet_map_data.c | 72 ++++++++++--------- 3 files changed, 45 insertions(+), 33 deletions(-)
drivers/net/ethernet/qualcomm/rmnet/rmnet_handlers.c +4 -1
@@ -126,7 +126,10 @@ rmnet_map_ingress_handler(struct sk_buff *skb,consume_skb (skb); }else { -__rmnet_map_ingress_handler (skb, port); +if (rmnet_map_validate_packet_len (skb, port)) +__rmnet_map_ingress_handler (skb, port); +else +kfree_skb (skb); } }
drivers/net/ethernet/qualcomm/rmnet/rmnet_map.h +1 -0
@@ -59,5 +59,6 @@ void rmnet_map_tx_aggregate_init(struct rmnet_port *port);void rmnet_map_tx_aggregate_exit (struct rmnet_port *port);void rmnet_map_update_ul_agg_config (struct rmnet_port *port,u32 size,u32 count,u32 time); +u32 rmnet_map_validate_packet_len (struct sk_buff *skb,struct rmnet_port *port);#endif /* _RMNET_MAP_H_ */
drivers/net/ethernet/qualcomm/rmnet/rmnet_map_data.c +40 -32
94 lines not on this page · raw message
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 692/1067 net/smc: fix UAF in smc_cdc_rx_handler() by pinning the socket
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
[ Upstream commit 9d160b35cc34a2ba8229d07651468a7848325135 ]
smc_cdc_rx_handler() looks up the connection by token under the link group's conns_lock, drops the lock, and then dereferences conn and the smc_sock derived from it, ending in sock_hold(&smc->sk) inside smc_cdc_msg_recv(). No reference is held across the lock release.
The only reference pinning the socket while the connection is discoverable in the link group is taken in smc_lgr_register_conn() (sock_hold) and dropped in __smc_lgr_unregister_conn() (sock_put), both under conns_lock. Once the handler drops conns_lock, a concurrent close() -> smc_release() -> smc_conn_free() -> smc_lgr_unregister_conn() can drop that reference and free the smc_sock, so the handler's later sock_hold() runs on freed memory:
WARNING: lib/refcount.c:25 at refcount_warn_saturate Workqueue: rxe_wq do_work refcount_warn_saturate (lib/refcount.c:25) smc_cdc_msg_recv (net/smc/smc_cdc.c:430) smc_cdc_rx_handler (net/smc/smc_cdc.c:502) smc_wr_rx_tasklet_fn (net/smc/smc_wr.c:445) tasklet_action_common (kernel/softirq.c:938) handle_softirqs (kernel/softirq.c:622) Kernel panic - not syncing: panic_on_warn set
Only SMC-R is affected. The SMC-D receive tasklet is stopped by tasklet_kill(&conn->rx_tsklet) in smc_conn_free() before the connection is unregistered, so it cannot run concurrently with the free.
Take the socket reference while still holding conns_lock, so the registration reference can no longer be the last one, and drop it once the handler is done.
--- net/smc/smc_cdc.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-)
net/smc/smc_cdc.c +10 -5
@@ -438,9 +438,9 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) {struct smc_link *link = (struct smc_link *)wc->qp->qp_context;struct smc_cdc_msg *cdc = buf; +struct smc_sock *smc =NULL ;struct smc_connection *conn;struct smc_link_group *lgr; -struct smc_sock *smc;if (wc->byte_len < offsetof(struct smc_cdc_msg , reserved))return ;/* short message */
@@ -451,21 +451,26 @@ static void smc_cdc_rx_handler(struct ib_wc *wc, void *buf) lgr =smc_get_lgr (link);read_lock_bh (&lgr->conns_lock); conn =smc_lgr_find_conn (ntohl (cdc->token), lgr); -read_unlock_bh (&lgr->conns_lock); -if (!conn || conn->out_of_sync) +if (!conn || conn->out_of_sync) { +read_unlock_bh (&lgr->conns_lock);return ; + } smc = container_of(conn, struct smc_sock, conn); +sock_hold (&smc->sk); +read_unlock_bh (&lgr->conns_lock);if (cdc->prod_flags.failover_validation) {smc_cdc_msg_validate (smc, cdc, link); -return ; + goto out; }if (smc_cdc_before (ntohs (cdc->seqno), conn->local_rx_ctrl.seqno))/* received seqno is old */ -return ; + goto out;smc_cdc_msg_recv (smc, cdc); +out: +sock_put (&smc->sk); }static struct smc_wr_rx_handler smc_cdc_rx_handlers[] = {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 693/1067 amt: fix size calculation in amt_get_size()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 9e05e91a9a847ed57926414bd7c2c5e54d6c56c6 ]
amt_get_size() incorrectly used sizeof(struct iphdr) for the sizes of IFLA_AMT_DISCOVERY_IP, IFLA_AMT_REMOTE_IP, and IFLA_AMT_LOCAL_IP. These attributes contain IPv4 addresses (__be32), not full IP headers.
Replace sizeof(struct iphdr) with sizeof(__be32) to avoid over-allocating netlink message space.
--- drivers/net/amt.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/net/amt.c +3 -3
@@ -3303,9 +3303,9 @@ static size_t amt_get_size(const struct net_device *dev)nla_total_size (sizeof (__u16)) +/* IFLA_AMT_GATEWAY_PORT */ nla_total_size (sizeof (__u32)) +/* IFLA_AMT_LINK */ nla_total_size (sizeof (__u32)) +/* IFLA_MAX_TUNNELS */ -nla_total_size (sizeof (struct iphdr )) +/* IFLA_AMT_DISCOVERY_IP */ -nla_total_size (sizeof (struct iphdr )) +/* IFLA_AMT_REMOTE_IP */ -nla_total_size (sizeof (struct iphdr ));/* IFLA_AMT_LOCAL_IP */ +nla_total_size (sizeof (__be32)) +/* IFLA_AMT_DISCOVERY_IP */ +nla_total_size (sizeof (__be32)) +/* IFLA_AMT_REMOTE_IP */ +nla_total_size (sizeof (__be32));/* IFLA_AMT_LOCAL_IP */ }static int amt_fill_info (struct sk_buff *skb,const struct net_device *dev)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 694/1067 Bluetooth: MGMT: Fix adv monitor add failure cleanup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cen Zhang <[email protected]>
[ Upstream commit 384a4b2fef9ffe5e270ee5558975c0504881c5fb ]
hci_add_adv_monitor() publishes a new adv_monitor in hdev->adv_monitors_idr before the powered MSFT setup step. The MSFT offload add path can then fail either locally before the controller add command completes, or in the MSFT add callback. In the current queued management add flow, hci_cmd_sync_work() still invokes mgmt_add_adv_patterns_monitor_complete() with the original pending command after msft_add_monitor_pattern() returns.
The buggy scenario involves two paths, with each column showing the order within that path:
MSFT add handling MGMT completion 1. insert monitor and handle 1. receive sync error 2. send MSFT add command 2. call add-monitor completion 3. callback sees bad response 3. load cmd->user_data 4. callback frees monitor 4. read monitor->handle
Local MSFT setup failures have the other half of the same ownership bug:
they return an error after the IDR insertion, but no later code removes the failed monitor from the IDR.
Keep ownership with the pending management command until its completion. For normal management adds, the MSFT add callback now records successful controller state and returns errors to its caller. The management completion frees the monitor on non-success after copying the response handle, while resume/reregister callback-error cleanup remains in the MSFT callback. The success path keeps the existing bookkeeping.
Validation reproduced this kernel report:
BUG: KASAN: slab-use-after-free in mgmt_add_adv_patterns_monitor_complete+0xfb/0x260 [bluetooth] Call Trace: <TASK> dump_stack_lvl+0x66/0xa0 print_report+0xce/0x5f0 ? mgmt_add_adv_patterns_monitor_complete+0xfb/0x260 [bluetooth] ? srso_alias_return_thunk+0x5/0xfbef5 ? __virt_addr_valid+0x19f/0x330 ? mgmt_add_adv_patterns_monitor_complete+0xfb/0x260 [bluetooth] kasan_report+0xe0/0x110 ? mgmt_add_adv_patterns_monitor_complete+0xfb/0x260 [bluetooth] mgmt_add_adv_patterns_monitor_complete+0xfb/0x260 [bluetooth] ? srso_alias_return_thunk+0x5/0xfbef5 ? 0xffffffffc00d00da ? __pfx_mgmt_add_adv_patterns_monitor_complete+0x10/0x10 [bluetooth] ? __pfx_mgmt_add_adv_patterns_monitor_complete+0x10/0x10 [bluetooth] ? hci_cmd_sync_work+0x1ab/0x210 [bluetooth] hci_cmd_sync_work+0x1c0/0x210 [bluetooth] ? __pfx_mgmt_add_adv_patterns_monitor_complete+0x10/0x10 [bluetooth] process_one_work+0x4fd/0xbc0 ? __pfx_process_one_work+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? srso_alias_return_thunk+0x5/0xfbef5 ? __list_add_valid_or_report+0x37/0xf0 ? __pfx_hci_cmd_sync_work+0x10/0x10 [bluetooth] ? srso_alias_return_thunk+0x5/0xfbef5 worker_thread+0x2d8/0x570 ? __pfx_worker_thread+0x10/0x10 kthread+0x1ad/0x1f0 ? __pfx_kthread+0x10/0x10 ret_from_fork+0x3c9/0x540 ? __pfx_ret_from_fork+0x10/0x10 ? srso_alias_return_thunk+0x5/0xfbef5 ? __switch_to+0x2e9/0x730 ? __pfx_kthread+0x10/0x10 ret_from_fork_asm+0x1a/0x30 </TASK> Allocated by task 471 on cpu 3 at 285.205389s: kasan_save_stack+0x33/0x60 kasan_save_track+0x17/0x60 __kasan_kmalloc+0xaa/0xb0 add_adv_patterns_monitor_rssi+0xd5/0x230 [bluetooth] hci_sock_sendmsg+0x96b/0xf80 [bluetooth] __sys_sendto+0x2bc/0x2d0 __x64_sys_sendto+0x76/0x90 do_syscall_64+0x115/0x6a0 entry_SYSCALL_64_after_hwframe+0x77/0x7f Freed by task 454 on cpu 2 at 285.217112s: kasan_save_stack+0x33/0x60 kasan_save_track+0x17/0x60 kasan_save_free_info+0x3b/0x60 __kasan_slab_free+0x5f/0x80 kfree+0x313/0x590 msft_add_monitor_sync+0x54a/0x570 [bluetooth] hci_add_adv_monitor+0x133/0x180 [bluetooth] hci_cmd_sync_work+0x187/0x210 [bluetooth] process_one_work+0x4fd/0xbc0 worker_thread+0x2d8/0x570 kthread+0x1ad/0x1f0 ret_from_fork+0x3c9/0x540 ret_from_fork_asm+0x1a/0x30
--- net/bluetooth/mgmt.c | 2 ++ net/bluetooth/msft.c | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-)
net/bluetooth/mgmt.c +2 -0
@@ -5343,6 +5343,8 @@ static void mgmt_add_adv_patterns_monitor_complete(struct hci_dev *hdev,if (monitor->state ==ADV_MONITOR_STATE_NOT_REGISTERED ) monitor->state =ADV_MONITOR_STATE_REGISTERED ;hci_update_passive_scan (hdev); + }else { +hci_free_adv_monitor (hdev, monitor); } mgmt_cmd_complete(cmd->sk, cmd->index, cmd->opcode,
net/bluetooth/msft.c +1 -1
@@ -246,7 +246,7 @@ static int msft_le_monitor_advertisement_cb(struct hci_dev *hdev, u16 opcode, monitor->state =ADV_MONITOR_STATE_OFFLOADED ; unlock: -if (status) +if (status && msft->resuming)hci_free_adv_monitor (hdev, monitor);hci_dev_unlock (hdev);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 695/1067 Bluetooth: ISO: exclude RFU bits from ISO_SDU_Length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
[ Upstream commit fd076d8deeab6f9f18ef13400f89e1f550df665b ]
slen contains ISO_SDU_Length (12 bits), RFU (2 bits), Packet_Status_Flags (2 bits).
Exclude the RFU bits from hci_iso_data_len. Also add masks to the pack macro.
--- include/net/bluetooth/hci.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
include/net/bluetooth/hci.h +3 -2
@@ -2969,8 +2969,9 @@ static inline struct hci_sco_hdr *hci_sco_hdr(const struct sk_buff *skb)#define hci_iso_flags_pack (pb, ts) ((pb & 0x03) | ((ts & 0x01) << 2))/* ISO data length and flags pack/unpack */ -#define hci_iso_data_len_pack (h, f) ((__u16) ((h) | ((f) << 14))) -#define hci_iso_data_len (h) ((h) & 0x3fff) +#define hci_iso_data_len_pack (h, f) ((__u16) (((h) & 0x0fff) | \ + (((f) & 0x3) << 14))) +#define hci_iso_data_len (h) ((h) & 0x0fff)#define hci_iso_data_flags (h) ((h) >> 14)/* codec transport types */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 696/1067 Bluetooth: bpa10x: avoid OOB read of revision string in bpa10x_setup()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
[ Upstream commit dd068ef044128db655f48323a4acfd5907e04903 ]
bpa10x_setup() sends the vendor command 0xfc0e and passes the response to bt_dev_info() and hci_set_fw_info() as a "%s" string starting at skb->data + 1, without checking the length:
bt_dev_info(hdev, "%s", (char *)(skb->data + 1)); hci_set_fw_info(hdev, "%s", skb->data + 1);
A device that returns a one-byte response (status only) leaves skb->data + 1 past the end of the data, and the %s walk reads adjacent slab memory until it meets a NUL. The same happens when the payload is not NUL-terminated within skb->len. The out-of-bounds bytes end up in the kernel log and the firmware-info debugfs file.
Print the revision string with a bounded "%.*s" limited to skb->len - 1 instead. This keeps the string readable for well-behaved devices while never reading past the received data, and does not fail setup, so a device returning a short or unterminated response keeps working.
--- drivers/bluetooth/bpa10x.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/bluetooth/bpa10x.c +6 -2
@@ -254,9 +254,13 @@ static int bpa10x_setup(struct hci_dev *hdev)if (IS_ERR (skb))return PTR_ERR (skb); -bt_dev_info (hdev,"%s" , (char *)(skb->data +1 )); +/* Bounded print: the device controls skb->len. */ +if (skb->len >1 ) { +int len = skb->len -1 ; -hci_set_fw_info (hdev,"%s" , skb->data +1 ); +bt_dev_info (hdev,"%.*s" , len, (char *)(skb->data +1 )); +hci_set_fw_info (hdev,"%.*s" , len, skb->data +1 ); + }kfree_skb (skb);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 697/1067 ring-buffer: Fix event length with forced 8-byte alignment
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hui Wang <[email protected]>
[ Upstream commit c37e0a4b79a6bbb96ce5ffe279d7c001e20529e0 ]
When RB_FORCE_8BYTE_ALIGNMENT is true, rb_calculate_event_length() reserves the space of event->array[0] for placing the data length and rb_update_event() stores the data length in event->array[0] accordingly. As a result the whole event length will add extra 4 bytes for sizeof(event.array[0]) unconditionally.
But ring_buffer_event_length() only subtracts the sizeof(event->array[0]) for events larger than RB_MAX_SMALL_DATA + sizeof(event->array[0]). As a result, small events on architectures with RB_FORCE_8BYTE_ALIGNMENT=true report a data length that is 4 bytes larger than expected.
To fix it, add the RB_FORCE_8BYTE_ALIGNMENT as a condition to subtract the size of that length field whenever RB_FORCE_8BYTE_ALIGNMENT is true.
This issue is observed in a riscv64 kernel with CONFIG_HAVE_64BIT_ALIGNED_ACCESS set to y, when we run ftrace selftest trace_marker_raw.tc, we get the weird log: for cases where the id is 1..100, the number of data field is 8*N, but once id exceeds 100, the number of data field becomes 8*N+4:
# 1 buf: 58 00 00 00 80 5e d1 63 (number of data field is 8*1)
...
# a buf: 58 ... (number of data field is 8*2) ... # 64 buf: 58 ... (number of data field is 8*13) # 65 buf: 58 ... (number of data field is 8*13+4)
After applying this change, the number of data field keeps being 8*N+4 consistently.
--- kernel/trace/ring_buffer.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
kernel/trace/ring_buffer.c +2 -1
@@ -255,7 +255,8 @@ unsigned ring_buffer_event_length(struct ring_buffer_event *event)if (event->type_len >RINGBUF_TYPE_DATA_TYPE_LEN_MAX )return length; length -=RB_EVNT_HDR_SIZE ; -if (length >RB_MAX_SMALL_DATA +sizeof (event->array[0 ])) +if (length >RB_MAX_SMALL_DATA +sizeof (event->array[0 ]) || +RB_FORCE_8BYTE_ALIGNMENT ) length -=sizeof (event->array[0 ]);return length; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 698/1067 net: usb: lan78xx: move functions to avoid forward definitions
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oleksij Rempel <[email protected]>
[ Upstream commit 39aa1d620d10cdd276f4728da50f136dbe939643 ]
Move following functions to avoid forward declarations in the code:
- lan78xx_start_hw()
- lan78xx_stop_hw()
- lan78xx_flush_fifo()
- lan78xx_start_tx_path()
- lan78xx_stop_tx_path()
- lan78xx_flush_tx_fifo()
- lan78xx_start_rx_path()
- lan78xx_stop_rx_path()
- lan78xx_flush_rx_fifo()
These functions will be used in an upcoming PHYlink migration patch.
No modifications to the functionality of the code are made.
Stable-dep-of: 60444706aa17 ("net: usb: lan78xx: disable VLAN filter in promiscuous mode")
--- drivers/net/usb/lan78xx.c | 300 +++++++++++++++++++------------------- 1 file changed, 150 insertions(+), 150 deletions(-)
drivers/net/usb/lan78xx.c +150 -150
@@ -817,6 +817,156 @@ static void lan78xx_update_stats(struct lan78xx_net *dev)usb_autopm_put_interface (dev->intf); } +static int lan78xx_start_hw (struct lan78xx_net *dev,u32 reg,u32 hw_enable) +{ +return lan78xx_update_reg (dev, reg, hw_enable, hw_enable); +} + +static int lan78xx_stop_hw (struct lan78xx_net *dev,u32 reg,u32 hw_enabled, +u32 hw_disabled) +{ +unsigned long timeout; +bool stopped = true; +int ret; +u32 buf; + +/* Stop the h/w block (if not already stopped) */ + + ret =lan78xx_read_reg (dev, reg, &buf); +if (ret <0 ) +return ret; + +if (buf & hw_enabled) { + buf &= ~hw_enabled; + + ret =lan78xx_write_reg (dev, reg, buf); +if (ret <0 ) +return ret; + + stopped = false; + timeout = jiffies +HW_DISABLE_TIMEOUT ; +do { + ret =lan78xx_read_reg (dev, reg, &buf); +if (ret <0 ) +return ret; + +if (buf & hw_disabled) + stopped = true; +else +msleep (HW_DISABLE_DELAY_MS ); + }while (!stopped && !time_after (jiffies, timeout)); + } + + ret = stopped ?0 : -ETIME ; + +return ret; +} + +static int lan78xx_flush_fifo (struct lan78xx_net *dev,u32 reg,u32 fifo_flush) +{ +return lan78xx_update_reg (dev, reg, fifo_flush, fifo_flush); +} + +static int lan78xx_start_tx_path (struct lan78xx_net *dev) +{ +int ret; + +netif_dbg (dev, drv, dev->net,"start tx path" ); + +/* Start the MAC transmitter */ + + ret =lan78xx_start_hw (dev,MAC_TX ,MAC_TX_TXEN_ ); +if (ret <0 ) +return ret; + +/* Start the Tx FIFO */ + + ret =lan78xx_start_hw (dev,FCT_TX_CTL ,FCT_TX_CTL_EN_ ); +if (ret <0 ) +return ret; + +return 0 ; +} + +static int lan78xx_stop_tx_path (struct lan78xx_net *dev) +{ +int ret; + +netif_dbg (dev, drv, dev->net,"stop tx path" ); + +/* Stop the Tx FIFO */ + + ret =lan78xx_stop_hw (dev,FCT_TX_CTL ,FCT_TX_CTL_EN_ ,FCT_TX_CTL_DIS_ ); +if (ret <0 ) +return ret; + +/* Stop the MAC transmitter */ + + ret =lan78xx_stop_hw (dev,MAC_TX ,MAC_TX_TXEN_ ,MAC_TX_TXD_ ); +if (ret <0 ) +return ret; + +return 0 ; +} + +/* The caller must ensure the Tx path is stopped before calling +* lan78xx_flush_tx_fifo(). +*/ +static int lan78xx_flush_tx_fifo (struct lan78xx_net *dev) +{ +return lan78xx_flush_fifo (dev,FCT_TX_CTL ,FCT_TX_CTL_RST_ ); +} + +static int lan78xx_start_rx_path (struct lan78xx_net *dev) +{ +int ret; + +netif_dbg (dev, drv, dev->net,"start rx path" ); + +/* Start the Rx FIFO */ + + ret =lan78xx_start_hw (dev,FCT_RX_CTL ,FCT_RX_CTL_EN_ ); +if (ret <0 ) +return ret; + +/* Start the MAC receiver*/ + + ret =lan78xx_start_hw (dev,MAC_RX ,MAC_RX_RXEN_ ); +if (ret <0 ) +return ret; + +return 0 ; +} + +static int lan78xx_stop_rx_path (struct lan78xx_net *dev) +{ +int ret; + +netif_dbg (dev, drv, dev->net,"stop rx path" ); + +/* Stop the MAC receiver */ + + ret =lan78xx_stop_hw (dev,MAC_RX ,MAC_RX_RXEN_ ,MAC_RX_RXD_ ); +if (ret <0 ) +return ret; + +/* Stop the Rx FIFO */ + + ret =lan78xx_stop_hw (dev,FCT_RX_CTL ,FCT_RX_CTL_EN_ ,FCT_RX_CTL_DIS_ ); +if (ret <0 ) +return ret; + +return 0 ; +} + +/* The caller must ensure the Rx path is stopped before calling +* lan78xx_flush_rx_fifo(). +*/ +static int lan78xx_flush_rx_fifo (struct lan78xx_net *dev) +{ +return lan78xx_flush_fifo (dev,FCT_RX_CTL ,FCT_RX_CTL_RST_ ); +} +/* Loop until the read is completed with timeout called with phy_mutex held */ static int lan78xx_phy_wait_not_busy (struct lan78xx_net *dev) {
@@ -2747,156 +2897,6 @@ static int lan78xx_urb_config_init(struct lan78xx_net *dev)return result; } -static int lan78xx_start_hw (struct lan78xx_net *dev,u32 reg,u32 hw_enable) -{ -return lan78xx_update_reg (dev, reg, hw_enable, hw_enable); -} - -static int lan78xx_stop_hw (struct lan78xx_net *dev,u32 reg,u32 hw_enabled, -u32 hw_disabled) -{ -unsigned long timeout; -bool stopped = true; -int ret; -u32 buf; - -/* Stop the h/w block (if not already stopped) */ - - ret =lan78xx_read_reg (dev, reg, &buf); -if (ret <0 ) -return ret; - -if (buf & hw_enabled) { - buf &= ~hw_enabled; - - ret =lan78xx_write_reg (dev, reg, buf); -if (ret <0 ) -return ret; - - stopped = false; - timeout = jiffies +HW_DISABLE_TIMEOUT ; -do { - ret =lan78xx_read_reg (dev, reg, &buf); -if (ret <0 ) -return ret; - -if (buf & hw_disabled) - stopped = true; -else -msleep (HW_DISABLE_DELAY_MS ); - }while (!stopped && !time_after (jiffies, timeout)); - } - - ret = stopped ?0 : -ETIME ; - -return ret; -} - -static int lan78xx_flush_fifo (struct lan78xx_net *dev,u32 reg,u32 fifo_flush) -{ -return lan78xx_update_reg (dev, reg, fifo_flush, fifo_flush); -} - -static int lan78xx_start_tx_path (struct lan78xx_net *dev) -{ -int ret; - -netif_dbg (dev, drv, dev->net,"start tx path" ); - -/* Start the MAC transmitter */ - - ret =lan78xx_start_hw (dev,MAC_TX ,MAC_TX_TXEN_ ); -if (ret <0 ) -return ret; - -/* Start the Tx FIFO */ - - ret =lan78xx_start_hw (dev,FCT_TX_CTL ,FCT_TX_CTL_EN_ ); -if (ret <0 ) -return ret; - -return 0 ; -} - -static int lan78xx_stop_tx_path (struct lan78xx_net *dev) -{ -int ret; - -netif_dbg (dev, drv, dev->net,"stop tx path" ); - -/* Stop the Tx FIFO */ - - ret =lan78xx_stop_hw (dev,FCT_TX_CTL ,FCT_TX_CTL_EN_ ,FCT_TX_CTL_DIS_ ); -if (ret <0 ) -return ret; - -/* Stop the MAC transmitter */ - - ret =lan78xx_stop_hw (dev,MAC_TX ,MAC_TX_TXEN_ ,MAC_TX_TXD_ ); -if (ret <0 ) -return ret; - -return 0 ; -} - -/* The caller must ensure the Tx path is stopped before calling -* lan78xx_flush_tx_fifo(). -*/ -static int lan78xx_flush_tx_fifo (struct lan78xx_net *dev) -{ -return lan78xx_flush_fifo (dev,FCT_TX_CTL ,FCT_TX_CTL_RST_ ); -} - -static int lan78xx_start_rx_path (struct lan78xx_net *dev) -{ -int ret; - -netif_dbg (dev, drv, dev->net,"start rx path" ); - -/* Start the Rx FIFO */ - - ret =lan78xx_start_hw (dev,FCT_RX_CTL ,FCT_RX_CTL_EN_ ); -if (ret <0 ) -return ret; - -/* Start the MAC receiver*/ - - ret =lan78xx_start_hw (dev,MAC_RX ,MAC_RX_RXEN_ ); -if (ret <0 ) -return ret; - -return 0 ; -} - -static int lan78xx_stop_rx_path (struct lan78xx_net *dev) -{ -int ret; - -netif_dbg (dev, drv, dev->net,"stop rx path" ); - -/* Stop the MAC receiver */ - - ret =lan78xx_stop_hw (dev,MAC_RX ,MAC_RX_RXEN_ ,MAC_RX_RXD_ ); -if (ret <0 ) -return ret; - -/* Stop the Rx FIFO */ - - ret =lan78xx_stop_hw (dev,FCT_RX_CTL ,FCT_RX_CTL_EN_ ,FCT_RX_CTL_DIS_ ); -if (ret <0 ) -return ret; - -return 0 ; -} - -/* The caller must ensure the Rx path is stopped before calling -* lan78xx_flush_rx_fifo(). -*/ -static int lan78xx_flush_rx_fifo (struct lan78xx_net *dev) -{ -return lan78xx_flush_fifo (dev,FCT_RX_CTL ,FCT_RX_CTL_RST_ ); -} -static int lan78xx_reset (struct lan78xx_net *dev) {struct lan78xx_priv *pdata = (struct lan78xx_priv *)(dev->data[0 ]);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 699/1067 net: usb: lan78xx: disable VLAN filter in promiscuous mode
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Enrico Pozzobon <[email protected]>
[ Upstream commit 60444706aa17616efc03190d099ac347e28b3d0a ]
The hardware VLAN filter (RFE_CTL_VLAN_FILTER_) drops VLAN-tagged frames whose VID has not been registered via lan78xx_vlan_rx_add_vid(). It is left enabled in promiscuous mode, so packet capture (e.g. tcpdump or Wireshark) does not see tagged frames for unregistered VIDs.
Clear the filter while the interface is promiscuous and restore it from NETIF_F_HW_VLAN_CTAG_FILTER otherwise. Enforce the same condition in lan78xx_set_features() so netdev_update_features() cannot re-enable the filter while promiscuous.
--- drivers/net/usb/lan78xx.c | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-)
drivers/net/usb/lan78xx.c +14 -4
@@ -1418,6 +1418,17 @@ static void lan78xx_deferred_multicast_write(struct work_struct *param)lan78xx_write_reg (dev,RFE_CTL , pdata->rfe_ctl); } +static void lan78xx_update_vlan_filter (struct lan78xx_priv *pdata, +struct net_device *netdev, +netdev_features_t features) +{ +if ((features &NETIF_F_HW_VLAN_CTAG_FILTER ) && + !(netdev->flags &IFF_PROMISC )) + pdata->rfe_ctl |=RFE_CTL_VLAN_FILTER_ ; +else + pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_ ; +} +static void lan78xx_set_multicast (struct net_device *netdev) {struct lan78xx_net *dev =netdev_priv (netdev);
@@ -1452,6 +1463,8 @@ static void lan78xx_set_multicast(struct net_device *netdev) } } +lan78xx_update_vlan_filter (pdata, dev->net, dev->net->features); +if (netdev_mc_count (dev->net)) {struct netdev_hw_addr *ha;int i;
@@ -2756,10 +2769,7 @@ static int lan78xx_set_features(struct net_device *netdev,else pdata->rfe_ctl &= ~RFE_CTL_VLAN_STRIP_ ; -if (features &NETIF_F_HW_VLAN_CTAG_FILTER ) - pdata->rfe_ctl |=RFE_CTL_VLAN_FILTER_ ; -else - pdata->rfe_ctl &= ~RFE_CTL_VLAN_FILTER_ ; +lan78xx_update_vlan_filter (pdata, netdev, features);spin_unlock_irqrestore (&pdata->rfe_ctl_lock, flags);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 700/1067 net/sched: cake: reject overhead values that underflow length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
[ Upstream commit b7f97cae7ec1b6c3c32843c42be218690d310467 ]
CAKE accepts signed overhead values and stores them in an s16, but the adjusted packet length calculation uses unsigned arithmetic. A negative effective length can therefore wrap to a large value.
Such configurations make rate accounting depend on integer wraparound rather than on the packet size userspace intended to model. A static netlink lower bound is not enough because packets reaching CAKE can be smaller than any reasonable manual-overhead allowance.
Fold the signed overhead adjustment into the existing datapath MPU clamp so negative adjusted lengths are clamped before link-layer framing adjustments.
--- net/sched/sch_cake.c | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-)
net/sched/sch_cake.c +1 -4
@@ -1381,10 +1381,7 @@ static u32 cake_calc_overhead(struct cake_sched_data *q, u32 len, u32 off)if (q->min_netlen > len) q->min_netlen = len; - len += q->rate_overhead; - -if (len < q->rate_mpu) - len = q->rate_mpu; + len =max ((s32 )len + q->rate_overhead, (s32 )q->rate_mpu);if (q->atm_mode ==CAKE_ATM_ATM ) { len +=47 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 701/1067 octeontx2-pf: check DMAC extraction support before filtering
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Suman Ghosh <[email protected]>
[ Upstream commit 235acadd310533ba386ae61ad155b72bee381559 ]
Currently, configuring a VF MAC address via the PF (e.g., 'ip link set <pf> vf 0 mac <mac>') blindly attempts to install a DMAC-based hardware filter. However, the hardware parser profile might not support DMAC extraction.
Check if the hardware parsing profile supports DMAC extraction before adding the filter. Additionally, emit a warning message to inform the operator if the MAC filter installation fails due to missing DMAC extraction support. Update config->mac only after hardware programming succeeds in otx2_set_vf_mac().
--- .../ethernet/marvell/octeontx2/nic/otx2_pf.c | 43 ++++++++++++++++--- 1 file changed, 37 insertions(+), 6 deletions(-)
drivers/net/ethernet/marvell/octeontx2/nic/otx2_pf.c +37 -6
@@ -2296,10 +2296,42 @@ EXPORT_SYMBOL(otx2_ioctl);static int otx2_do_set_vf_mac (struct otx2_nic *pf,int vf,const u8 *mac) { +struct npc_get_field_status_req *freq; +struct npc_get_field_status_rsp *frsp;struct npc_install_flow_req *req;int err;mutex_lock (&pf->mbox.lock); + +/* Skip installing the DMAC filter if the hardware parser profile +* does not support DMAC extraction. +*/ + freq =otx2_mbox_alloc_msg_npc_get_field_status (&pf->mbox); +if (!freq) { + err = -ENOMEM ; + goto out; + } + + freq->field =NPC_DMAC ; + err =otx2_sync_mbox_msg (&pf->mbox); +if (err) + goto out; + + frsp = (struct npc_get_field_status_rsp *)otx2_mbox_get_rsp + (&pf->mbox.mbox,0 , &freq->hdr); +if (IS_ERR (frsp)) { + err =PTR_ERR (frsp); + goto out; + } + +if (!frsp->enable) { +netdev_warn (pf->netdev, +"VF %d MAC filter not installed: DMAC extraction not supported by parser profile\n" , + vf); + err = -EOPNOTSUPP ; + goto out; + } + req =otx2_mbox_alloc_msg_npc_install_flow (&pf->mbox);if (!req) { err = -ENOMEM ;
@@ -2338,13 +2370,12 @@ static int otx2_set_vf_mac(struct net_device *netdev, int vf, u8 *mac)if (!is_valid_ether_addr (mac))return -EINVAL ; - config = &pf->vf_configs[vf]; -ether_addr_copy (config->mac, mac); - ret =otx2_do_set_vf_mac (pf, vf, mac); -if (ret ==0 ) -dev_info (&pdev->dev, -"Load/Reload VF driver\n" ); +if (ret ==0 ) { + config = &pf->vf_configs[vf]; +ether_addr_copy (config->mac, mac); +dev_info (&pdev->dev,"Load/Reload VF driver\n" ); + }return ret; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 702/1067 ipv6: mcast: Replace locking comments with lockdep annotations.
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuniyuki Iwashima <[email protected]>
[ Upstream commit 818ae1a5ecb41d82ad180a99c39111f051894d90 ]
Commit 63ed8de4be81 ("mld: add mc_lock for protecting per-interface mld data") added the same comments regarding locking to many functions.
Let's replace the comments with lockdep annotation, which is more helpful.
Note that we just remove the comment for mld_clear_zeros() and mld_send_cr(), where mc_dereference() is used in the entry of the function.
While at it, a comment for __ipv6_sock_mc_join() is moved back to the correct place.
Stable-dep-of: 9b26518b6896 ("ipv6: mcast: Fix potential UAF in MLD delayed work")
--- net/ipv6/mcast.c | 125 +++++++++++++++++++++++++++-------------------- 1 file changed, 71 insertions(+), 54 deletions(-)
net/ipv6/mcast.c +71 -54
@@ -105,9 +105,9 @@ static int __ipv6_dev_mc_inc(struct net_device *dev,int sysctl_mld_max_msf__read_mostly =IPV6_MLD_MAX_MSF ;int sysctl_mld_qrv__read_mostly =MLD_QRV_DEFAULT ; -/* -* socket join on multicast group -*/ +#define mc_assert_locked (idev) \ + lockdep_assert_held(&(idev)->mc_lock) +#define mc_dereference (e, idev) \ rcu_dereference_protected(e, lockdep_is_held(&(idev)->mc_lock))
@@ -166,6 +166,9 @@ static int unsolicited_report_interval(struct inet6_dev *idev)return iv >0 ? iv :1 ; } +/* +* socket join on multicast group +*/ static int __ipv6_sock_mc_join (struct sock *sk,int ifindex,const struct in6_addr *addr,unsigned int mode) {
@@ -664,12 +667,13 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,return rv; } -/* called with mc_lock */ static void igmp6_group_added (struct ifmcaddr6 *mc) {struct net_device *dev = mc->idev->dev;char buf[MAX_ADDR_LEN ]; +mc_assert_locked (mc->idev); +if (IPV6_ADDR_MC_SCOPE (&mc->mca_addr) <IPV6_ADDR_SCOPE_LINKLOCAL )return ;
@@ -699,12 +703,13 @@ static void igmp6_group_added(struct ifmcaddr6 *mc)mld_ifc_event (mc->idev); } -/* called with mc_lock */ static void igmp6_group_dropped (struct ifmcaddr6 *mc) {struct net_device *dev = mc->idev->dev;char buf[MAX_ADDR_LEN ]; +mc_assert_locked (mc->idev); +if (IPV6_ADDR_MC_SCOPE (&mc->mca_addr) <IPV6_ADDR_SCOPE_LINKLOCAL )return ;
@@ -725,14 +730,13 @@ static void igmp6_group_dropped(struct ifmcaddr6 *mc)refcount_dec (&mc->mca_refcnt); } -/* -* deleted ifmcaddr6 manipulation -* called with mc_lock -*/ +/* deleted ifmcaddr6 manipulation */ static void mld_add_delrec (struct inet6_dev *idev,struct ifmcaddr6 *im) {struct ifmcaddr6 *pmc; +mc_assert_locked (idev); +/* this is an "ifmcaddr6" for convenience; only the fields below * are actually used. In particular, the refcnt and users are not * used for management of the delete list. Using the same structure
@@ -766,13 +770,14 @@ static void mld_add_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)rcu_assign_pointer (idev->mc_tomb, pmc); } -/* called with mc_lock */ static void mld_del_delrec (struct inet6_dev *idev,struct ifmcaddr6 *im) {struct ip6_sf_list *psf, *sources, *tomb;struct in6_addr *pmca = &im->mca_addr;struct ifmcaddr6 *pmc, *pmc_prev; +mc_assert_locked (idev); + pmc_prev =NULL ;for_each_mc_tomb (idev, pmc) {if (ipv6_addr_equal (&pmc->mca_addr, pmca))
@@ -809,11 +814,12 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) } } -/* called with mc_lock */ static void mld_clear_delrec (struct inet6_dev *idev) {struct ifmcaddr6 *pmc, *nextpmc; +mc_assert_locked (idev); + pmc =mc_dereference (idev->mc_tomb, idev);RCU_INIT_POINTER (idev->mc_tomb,NULL );
@@ -870,13 +876,14 @@ static void ma_put(struct ifmcaddr6 *mc) } } -/* called with mc_lock */ static struct ifmcaddr6 *mca_alloc (struct inet6_dev *idev,const struct in6_addr *addr,unsigned int mode) {struct ifmcaddr6 *mc; +mc_assert_locked (idev); + mc =kzalloc (sizeof (*mc),GFP_KERNEL );if (!mc)return NULL ;
@@ -1046,46 +1053,51 @@ bool ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,return rv; } -/* called with mc_lock */ static void mld_gq_start_work (struct inet6_dev *idev) {unsigned long tv =prandom_u32_max (idev->mc_maxdelay); +mc_assert_locked (idev); + idev->mc_gq_running =1 ;if (!mod_delayed_work (mld_wq, &idev->mc_gq_work, tv +2 ))in6_dev_hold (idev); } -/* called with mc_lock */ static void mld_gq_stop_work (struct inet6_dev *idev) { +mc_assert_locked (idev); + idev->mc_gq_running =0 ;if (cancel_delayed_work (&idev->mc_gq_work))__in6_dev_put (idev); } -/* called with mc_lock */ static void mld_ifc_start_work (struct inet6_dev *idev,unsigned long delay) {unsigned long tv =prandom_u32_max (delay); +mc_assert_locked (idev); +if (!mod_delayed_work (mld_wq, &idev->mc_ifc_work, tv +2 ))in6_dev_hold (idev); } -/* called with mc_lock */ static void mld_ifc_stop_work (struct inet6_dev *idev) { +mc_assert_locked (idev); + idev->mc_ifc_count =0 ;if (cancel_delayed_work (&idev->mc_ifc_work))__in6_dev_put (idev); } -/* called with mc_lock */ static void mld_dad_start_work (struct inet6_dev *idev,unsigned long delay) {unsigned long tv =prandom_u32_max (delay); +mc_assert_locked (idev); +if (!mod_delayed_work (mld_wq, &idev->mc_dad_work, tv +2 ))in6_dev_hold (idev); }
@@ -1110,14 +1122,13 @@ static void mld_report_stop_work(struct inet6_dev *idev)__in6_dev_put (idev); } -/* -* IGMP handling (alias multicast ICMPv6 messages) -* called with mc_lock -*/ +/* IGMP handling (alias multicast ICMPv6 messages) */ static void igmp6_group_queried (struct ifmcaddr6 *ma,unsigned long resptime) {unsigned long delay = resptime; +mc_assert_locked (ma->idev); +/* Do not start work for these addresses */ if (ipv6_addr_is_ll_all_nodes (&ma->mca_addr) ||IPV6_ADDR_MC_SCOPE (&ma->mca_addr) <IPV6_ADDR_SCOPE_LINKLOCAL )
@@ -1136,15 +1147,15 @@ static void igmp6_group_queried(struct ifmcaddr6 *ma, unsigned long resptime) ma->mca_flags |=MAF_TIMER_RUNNING ; } -/* mark EXCLUDE-mode sources -* called with mc_lock -*/ +/* mark EXCLUDE-mode sources */ static bool mld_xmarksources (struct ifmcaddr6 *pmc,int nsrcs,const struct in6_addr *srcs) {struct ip6_sf_list *psf;int i, scount; +mc_assert_locked (pmc->idev); + scount =0 ;for_each_psf_mclock (pmc, psf) {if (scount == nsrcs)
@@ -1167,13 +1178,14 @@ static bool mld_xmarksources(struct ifmcaddr6 *pmc, int nsrcs,return true; } -/* called with mc_lock */ static bool mld_marksources (struct ifmcaddr6 *pmc,int nsrcs,const struct in6_addr *srcs) {struct ip6_sf_list *psf;int i, scount; +mc_assert_locked (pmc->idev); +if (pmc->mca_sfmode ==MCAST_EXCLUDE )return mld_xmarksources (pmc, nsrcs, srcs);
@@ -1870,7 +1882,6 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,#define AVAILABLE (skb) ((skb) ? skb_availroom(skb) : 0) -/* called with mc_lock */ static struct sk_buff *add_grec (struct sk_buff *skb,struct ifmcaddr6 *pmc,int type,int gdeleted,int sdeleted,int crsend)
@@ -1884,6 +1895,8 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,struct mld2_report *pmr;unsigned int mtu; +mc_assert_locked (idev); +if (pmc->mca_flags &MAF_NOREPORT )return skb;
@@ -2002,12 +2015,13 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,return skb; } -/* called with mc_lock */ static void mld_send_report (struct inet6_dev *idev,struct ifmcaddr6 *pmc) {struct sk_buff *skb =NULL ;int type; +mc_assert_locked (idev); +if (!pmc) {for_each_mc_mclock (idev, pmc) {if (pmc->mca_flags &MAF_NOREPORT )
@@ -2029,10 +2043,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)mld_sendpack (skb); } -/* -* remove zero-count source records from a source filter list -* called with mc_lock -*/ +/* remove zero-count source records from a source filter list */ static void mld_clear_zeros (struct ip6_sf_list __rcu **ppsf,struct inet6_dev *idev) {struct ip6_sf_list *psf_prev, *psf_next, *psf;
@@ -2056,7 +2067,6 @@ static void mld_clear_zeros(struct ip6_sf_list __rcu **ppsf, struct inet6_dev *i } } -/* called with mc_lock */ static void mld_send_cr (struct inet6_dev *idev) {struct ifmcaddr6 *pmc, *pmc_prev, *pmc_next;
@@ -2222,13 +2232,14 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type) goto out; } -/* called with mc_lock */ static void mld_send_initial_cr (struct inet6_dev *idev) { -struct sk_buff *skb;struct ifmcaddr6 *pmc; +struct sk_buff *skb;int type; +mc_assert_locked (idev); +if (mld_in_v1_mode (idev))return ;
@@ -2275,13 +2286,14 @@ static void mld_dad_work(struct work_struct *work)in6_dev_put (idev); } -/* called with mc_lock */ static int ip6_mc_del1_src (struct ifmcaddr6 *pmc,int sfmode, -const struct in6_addr *psfsrc) +const struct in6_addr *psfsrc) {struct ip6_sf_list *psf, *psf_prev;int rv =0 ; +mc_assert_locked (pmc->idev); + psf_prev =NULL ;for_each_psf_mclock (pmc, psf) {if (ipv6_addr_equal (&psf->sf_addr, psfsrc))
@@ -2318,7 +2330,6 @@ static int ip6_mc_del1_src(struct ifmcaddr6 *pmc, int sfmode,return rv; } -/* called with mc_lock */ static int ip6_mc_del_src (struct inet6_dev *idev,const struct in6_addr *pmca,int sfmode,int sfcount,const struct in6_addr *psfsrc,int delta)
@@ -2330,6 +2341,8 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,if (!idev)return -ENODEV ; +mc_assert_locked (idev); +for_each_mc_mclock (idev, pmc) {if (ipv6_addr_equal (pmca, &pmc->mca_addr))break ;
@@ -2371,15 +2384,14 @@ static int ip6_mc_del_src(struct inet6_dev *idev, const struct in6_addr *pmca,return err; } -/* -* Add multicast single-source filter to the interface list -* called with mc_lock -*/ +/* Add multicast single-source filter to the interface list */ static int ip6_mc_add1_src (struct ifmcaddr6 *pmc,int sfmode, -const struct in6_addr *psfsrc) +const struct in6_addr *psfsrc) {struct ip6_sf_list *psf, *psf_prev; +mc_assert_locked (pmc->idev); + psf_prev =NULL ;for_each_psf_mclock (pmc, psf) {if (ipv6_addr_equal (&psf->sf_addr, psfsrc))
@@ -2402,11 +2414,12 @@ static int ip6_mc_add1_src(struct ifmcaddr6 *pmc, int sfmode,return 0 ; } -/* called with mc_lock */ static void sf_markstate (struct ifmcaddr6 *pmc) { -struct ip6_sf_list *psf;int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE ]; +struct ip6_sf_list *psf; + +mc_assert_locked (pmc->idev);for_each_psf_mclock (pmc, psf) {if (pmc->mca_sfcount[MCAST_EXCLUDE ]) {
@@ -2419,14 +2432,15 @@ static void sf_markstate(struct ifmcaddr6 *pmc) } } -/* called with mc_lock */ static int sf_setstate (struct ifmcaddr6 *pmc) { -struct ip6_sf_list *psf, *dpsf;int mca_xcount = pmc->mca_sfcount[MCAST_EXCLUDE ]; +struct ip6_sf_list *psf, *dpsf;int qrv = pmc->idev->mc_qrv;int new_in, rv; +mc_assert_locked (pmc->idev); + rv =0 ;for_each_psf_mclock (pmc, psf) {if (pmc->mca_sfcount[MCAST_EXCLUDE ]) {
@@ -2485,10 +2499,7 @@ static int sf_setstate(struct ifmcaddr6 *pmc)return rv; } -/* -* Add multicast source filter list to the interface list -* called with mc_lock -*/ +/* Add multicast source filter list to the interface list */ static int ip6_mc_add_src (struct inet6_dev *idev,const struct in6_addr *pmca,int sfmode,int sfcount,const struct in6_addr *psfsrc,int delta)
@@ -2500,6 +2511,8 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,if (!idev)return -ENODEV ; +mc_assert_locked (idev); +for_each_mc_mclock (idev, pmc) {if (ipv6_addr_equal (pmca, &pmc->mca_addr))break ;
@@ -2545,11 +2558,12 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,return err; } -/* called with mc_lock */ static void ip6_mc_clear_src (struct ifmcaddr6 *pmc) {struct ip6_sf_list *psf, *nextpsf; +mc_assert_locked (pmc->idev); +for (psf =mc_dereference (pmc->mca_tomb, pmc->idev); psf; psf = nextpsf) {
@@ -2569,11 +2583,12 @@ static void ip6_mc_clear_src(struct ifmcaddr6 *pmc) pmc->mca_sfcount[MCAST_EXCLUDE ] =1 ; } -/* called with mc_lock */ static void igmp6_join_group (struct ifmcaddr6 *ma) {unsigned long delay; +mc_assert_locked (ma->idev); +if (ma->mca_flags &MAF_NOREPORT )return ;
@@ -2620,9 +2635,10 @@ static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,return err; } -/* called with mc_lock */ static void igmp6_leave_group (struct ifmcaddr6 *ma) { +mc_assert_locked (ma->idev); +if (mld_in_v1_mode (ma->idev)) {if (ma->mca_flags &MAF_LAST_REPORTER ) { igmp6_send(&ma->mca_addr, ma->idev->dev,
@@ -2667,9 +2683,10 @@ static void mld_ifc_work(struct work_struct *work)in6_dev_put (idev); } -/* called with mc_lock */ static void mld_ifc_event (struct inet6_dev *idev) { +mc_assert_locked (idev); +if (mld_in_v1_mode (idev))return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 703/1067 ipv6: mcast: Fix potential UAF in MLD delayed work
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 9b26518b6896a16b809b1e42986f4ebac7bccc1e ]
A race condition exists between device teardown and incoming MLD query processing, leading to a Use-After-Free in the MLD delayed work.
During device destruction, the primary reference to inet6_dev is dropped, which can drop its refcount to 0. The actual freeing of inet6_dev memory is deferred via RCU.
Concurrently, the packet receive path runs under RCU read lock and obtains the inet6_dev pointer. Because the memory is RCU-protected, CPU-0 can safely dereference inet6_dev even if its refcount has hit 0.
However, if CPU-0 calls igmp6_event_query() and schedules delayed work, it attempts to acquire a reference using in6_dev_hold(). This increments the refcount from 0 to 1, triggering a "refcount_t: addition on 0" warning. Since the inet6_dev memory is still scheduled to be freed after the RCU grace period, the device is freed while the work is still scheduled. When the work runs, it accesses the freed memory, causing a kernel panic.
Fix this by using refcount_inc_not_zero() (via a new helper in6_dev_hold_safe()) to prevent acquiring a reference if the device is already being destroyed. If the refcount is 0, we do not schedule the work.
--- include/net/addrconf.h | 5 +++++ net/ipv6/mcast.c | 40 ++++++++++++++++++++++++++++------------ 2 files changed, 33 insertions(+), 12 deletions(-)
include/net/addrconf.h +5 -0
@@ -411,6 +411,11 @@ static inline void in6_dev_hold(struct inet6_dev *idev)refcount_inc (&idev->refcnt); } +static inline bool in6_dev_hold_safe (struct inet6_dev *idev) +{ +return refcount_inc_not_zero (&idev->refcnt); +} +/* called with rcu_read_lock held */ static inline bool ip6_ignore_linkdown (const struct net_device *dev) {
net/ipv6/mcast.c +28 -12
@@ -1060,8 +1060,10 @@ static void mld_gq_start_work(struct inet6_dev *idev)mc_assert_locked (idev); idev->mc_gq_running =1 ; -if (!mod_delayed_work (mld_wq, &idev->mc_gq_work, tv +2 )) -in6_dev_hold (idev); +if (in6_dev_hold_safe (idev)) { +if (mod_delayed_work (mld_wq, &idev->mc_gq_work, tv +2 )) +in6_dev_put (idev); + } }static void mld_gq_stop_work (struct inet6_dev *idev)
@@ -1079,8 +1081,10 @@ static void mld_ifc_start_work(struct inet6_dev *idev, unsigned long delay)mc_assert_locked (idev); -if (!mod_delayed_work (mld_wq, &idev->mc_ifc_work, tv +2 )) -in6_dev_hold (idev); +if (in6_dev_hold_safe (idev)) { +if (mod_delayed_work (mld_wq, &idev->mc_ifc_work, tv +2 )) +in6_dev_put (idev); + } }static void mld_ifc_stop_work (struct inet6_dev *idev)
@@ -1098,8 +1102,10 @@ static void mld_dad_start_work(struct inet6_dev *idev, unsigned long delay)mc_assert_locked (idev); -if (!mod_delayed_work (mld_wq, &idev->mc_dad_work, tv +2 )) -in6_dev_hold (idev); +if (in6_dev_hold_safe (idev)) { +if (mod_delayed_work (mld_wq, &idev->mc_dad_work, tv +2 )) +in6_dev_put (idev); + } }static void mld_dad_stop_work (struct inet6_dev *idev)
@@ -1385,18 +1391,23 @@ static void mld_process_v2(struct inet6_dev *idev, struct mld2_query *mld,void igmp6_event_query (struct sk_buff *skb) {struct inet6_dev *idev =__in6_dev_get (skb->dev); +bool put = false;if (!idev || idev->dead) goto out;spin_lock_bh (&idev->mc_query_lock); -if (skb_queue_len (&idev->mc_query_queue) <MLD_MAX_SKBS ) { +if (skb_queue_len (&idev->mc_query_queue) <MLD_MAX_SKBS && +in6_dev_hold_safe (idev)) {__skb_queue_tail (&idev->mc_query_queue, skb); -if (!mod_delayed_work (mld_wq, &idev->mc_query_work,0 )) -in6_dev_hold (idev); +if (mod_delayed_work (mld_wq, &idev->mc_query_work,0 )) + put = true; skb =NULL ; }spin_unlock_bh (&idev->mc_query_lock); + +if (put) +in6_dev_put (idev); out:kfree_skb (skb); }
@@ -1553,18 +1564,23 @@ static void mld_query_work(struct work_struct *work)void igmp6_event_report (struct sk_buff *skb) {struct inet6_dev *idev =__in6_dev_get (skb->dev); +bool put = false;if (!idev || idev->dead) goto out;spin_lock_bh (&idev->mc_report_lock); -if (skb_queue_len (&idev->mc_report_queue) <MLD_MAX_SKBS ) { +if (skb_queue_len (&idev->mc_report_queue) <MLD_MAX_SKBS && +in6_dev_hold_safe (idev)) {__skb_queue_tail (&idev->mc_report_queue, skb); -if (!mod_delayed_work (mld_wq, &idev->mc_report_work,0 )) -in6_dev_hold (idev); +if (mod_delayed_work (mld_wq, &idev->mc_report_work,0 )) + put = true; skb =NULL ; }spin_unlock_bh (&idev->mc_report_lock); + +if (put) +in6_dev_put (idev); out:kfree_skb (skb); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 704/1067 ipvs: pass parsed transport offset to state handlers
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
[ Upstream commit bae7ce7bafb59e42dc0e0e2999fdd9d1cffe3866 ]
IPVS callers already parse the packet into struct ip_vs_iphdr before updating connection state. For IPv6 this records the real transport-header offset after extension headers in iph.len.
Pass this parsed transport offset through ip_vs_set_state() and the protocol state_transition() callback so protocol handlers can use the same packet context as scheduling and NAT handling. This patch only changes the common callback plumbing and adapts the protocol callback signatures; TCP and SCTP start using the value in follow-up patches.
Stable-dep-of: 2500fa3958b1 ("ipvs: use parsed transport offset in TCP state lookup")
--- include/net/ip_vs.h | 3 ++- net/netfilter/ipvs/ip_vs_core.c | 10 +++++----- net/netfilter/ipvs/ip_vs_proto_sctp.c | 3 ++- net/netfilter/ipvs/ip_vs_proto_tcp.c | 3 ++- net/netfilter/ipvs/ip_vs_proto_udp.c | 3 ++- 5 files changed, 13 insertions(+), 9 deletions(-)
include/net/ip_vs.h +2 -1
@@ -455,7 +455,8 @@ struct ip_vs_protocol {void (*state_transition)(struct ip_vs_conn *cp,int direction,const struct sk_buff *skb, -struct ip_vs_proto_data *pd); +struct ip_vs_proto_data *pd, +unsigned int iph_len);int (*register_app)(struct netns_ipvs *ipvs,struct ip_vs_app *inc);
net/netfilter/ipvs/ip_vs_core.c +5 -5
@@ -220,10 +220,10 @@ ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc)static inline void ip_vs_set_state (struct ip_vs_conn *cp,int direction,const struct sk_buff *skb, -struct ip_vs_proto_data *pd) +struct ip_vs_proto_data *pd,unsigned int iph_len) {if (likely (pd->pp->state_transition)) - pd->pp->state_transition (cp, direction, skb, pd); + pd->pp->state_transition (cp, direction, skb, pd, iph_len); } static inline int
@@ -625,7 +625,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb,ip_vs_in_stats (cp, skb);/* set state */ -ip_vs_set_state (cp,IP_VS_DIR_INPUT , skb, pd); +ip_vs_set_state (cp,IP_VS_DIR_INPUT , skb, pd, iph->len);/* transmit the first SYN packet */ ret = cp->packet_xmit (skb, cp, pd->pp, iph);
@@ -1308,7 +1308,7 @@ handle_response(int af, struct sk_buff *skb, struct ip_vs_proto_data *pd, after_nat:ip_vs_out_stats (cp, skb); -ip_vs_set_state (cp,IP_VS_DIR_OUTPUT , skb, pd); +ip_vs_set_state (cp,IP_VS_DIR_OUTPUT , skb, pd, iph->len); skb->ipvs_property =1 ;if (!(cp->flags &IP_VS_CONN_F_NFCT ))ip_vs_notrack (skb);
@@ -2060,7 +2060,7 @@ ip_vs_in_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *stateIP_VS_DBG_PKT (11 , af, pp, skb, iph.off,"Incoming packet" );ip_vs_in_stats (cp, skb); -ip_vs_set_state (cp,IP_VS_DIR_INPUT , skb, pd); +ip_vs_set_state (cp,IP_VS_DIR_INPUT , skb, pd, iph.len);if (cp->packet_xmit) ret = cp->packet_xmit (skb, cp, pp, &iph);/* do not touch skb anymore */
net/netfilter/ipvs/ip_vs_proto_sctp.c +2 -1
@@ -468,7 +468,8 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,static void sctp_state_transition (struct ip_vs_conn *cp,int direction, -const struct sk_buff *skb,struct ip_vs_proto_data *pd) +const struct sk_buff *skb,struct ip_vs_proto_data *pd, +unsigned int iph_len) {spin_lock_bh (&cp->lock);set_sctp_state (pd, cp, direction, skb);
net/netfilter/ipvs/ip_vs_proto_tcp.c +2 -1
@@ -580,7 +580,8 @@ set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp,static void tcp_state_transition (struct ip_vs_conn *cp,int direction,const struct sk_buff *skb, -struct ip_vs_proto_data *pd) +struct ip_vs_proto_data *pd, +unsigned int iph_len) {struct tcphdr _tcph, *th;
net/netfilter/ipvs/ip_vs_proto_udp.c +2 -1
@@ -445,7 +445,8 @@ static const char * udp_state_name(int state)static void udp_state_transition (struct ip_vs_conn *cp,int direction,const struct sk_buff *skb, -struct ip_vs_proto_data *pd) +struct ip_vs_proto_data *pd, +unsigned int iph_len) {if (unlikely (!pd)) {pr_err ("UDP no ns data\n" );
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 705/1067 ipvs: use parsed transport offset in TCP state lookup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
[ Upstream commit 2500fa3958b1ba51c2b065e39db1b04dfa7e23a2 ]
TCP state handling reparses the skb to find the TCP header. For IPv6 it uses sizeof(struct ipv6hdr), while the surrounding IPVS code already parsed the packet with ip_vs_fill_iph_skb() and has the real transport-header offset in iph.len.
This makes TCP state handling look at the wrong bytes when an IPv6 packet carries extension headers. Use the parsed transport offset passed down from ip_vs_set_state() when reading the TCP header.
For IPv4 and for IPv6 packets without extension headers, the passed offset matches the previous value.
--- net/netfilter/ipvs/ip_vs_proto_tcp.c | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-)
net/netfilter/ipvs/ip_vs_proto_tcp.c +1 -7
@@ -585,13 +585,7 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction, {struct tcphdr _tcph, *th; -#ifdef CONFIG_IP_VS_IPV6 -int ihl = cp->af ==AF_INET ?ip_hdrlen (skb) :sizeof (struct ipv6hdr ); -#else -int ihl =ip_hdrlen (skb); -#endif - - th =skb_header_pointer (skb, ihl,sizeof (_tcph), &_tcph); + th =skb_header_pointer (skb, iph_len,sizeof (_tcph), &_tcph);if (th ==NULL )return ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 706/1067 ipvs: fix PMTU for GUE/GRE tunnel ICMP errors
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
[ Upstream commit 6b335af0d0d1ff44ac579d106953bf19299e5233 ]
When an ICMP Fragmentation Needed error is received for a tunneled IPVS connection, ip_vs_in_icmp() recomputes the MTU that the original packet can use by subtracting the tunnel overhead from the reported next-hop MTU.
The current code always subtracts sizeof(struct iphdr), which is only the IPIP overhead. For GUE and GRE tunnels, ipvs_udp_decap() and ipvs_gre_decap() already compute the additional tunnel header length, but that value is scoped to the decapsulation block and is lost before the ICMP_FRAG_NEEDED handling. As a result, the ICMP error sent back to the client advertises an MTU that is too large, so PMTUD can fail to converge for GUE/GRE-tunneled real servers.
With a reported next-hop MTU of 1400, a GUE tunnel currently returns 1380 to the client. The correct value is 1368:
1400 - sizeof(struct iphdr) - sizeof(struct udphdr) - sizeof(struct guehdr)
Hoist the tunnel header length into the main ip_vs_in_icmp() scope and subtract sizeof(struct iphdr) + ulen in the Fragmentation Needed path. The IPIP path keeps ulen as 0, so its existing 1400 - 20 = 1380 result is unchanged.
Stable-dep-of: 3f7a535ff0fa ("ipvs: ensure inner headers in ICMP errors are in headroom")
--- net/netfilter/ipvs/ip_vs_core.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/netfilter/ipvs/ip_vs_core.c +3 -3
@@ -1594,6 +1594,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,bool tunnel, new_cp = false;union nf_inet_addr *raddr;char *outer_proto ="IPIP" ; +int ulen =0 ; *related =1 ;
@@ -1658,7 +1659,6 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,/* Error for our tunnel must arrive at LOCAL_IN */ (skb_rtable(skb)->rt_flags & RTCF_LOCAL)) {__u8 iproto; -int ulen;/* Non-first fragment has no UDP/GRE header */ if (unlikely (cih->frag_off &htons (IP_OFFSET )))
@@ -1763,8 +1763,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,if (dest_dst) mtu =dst_mtu (dest_dst->dst_cache); } -if (mtu >68 +sizeof (struct iphdr )) - mtu -=sizeof (struct iphdr ); +if (mtu >68 +sizeof (struct iphdr ) + ulen) + mtu -=sizeof (struct iphdr ) + ulen; info =htonl (mtu); }/* Strip outer IP, ICMP and IPIP/UDP/GRE, go to IP header of
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 707/1067 ipvs: ensure inner headers in ICMP errors are in headroom
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Julian Anastasov <[email protected]>
[ Upstream commit 3f7a535ff0fa627a0132803e4c2f903ceffcbc1c ]
Sashiko points out that after stripping the outer headers with pskb_pull() we should ensure the inner IP headers in ICMP errors from tunnels are present in the skb headroom for functions like ipv4_update_pmtu(), icmp_send() and IP_VS_DBG().
Also, add more checks for the length of the inner headers.
--- net/netfilter/ipvs/ip_vs_core.c | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-)
net/netfilter/ipvs/ip_vs_core.c +15 -6
@@ -1594,6 +1594,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,bool tunnel, new_cp = false;union nf_inet_addr *raddr;char *outer_proto ="IPIP" ; +unsigned int hlen_ipip;int ulen =0 ; *related =1 ;
@@ -1631,9 +1632,10 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,/* Now find the contained IP header */ offset +=sizeof (_icmph); cih =skb_header_pointer (skb, offset,sizeof (_ciph), &_ciph); -if (cih ==NULL ) +if (!(cih && cih->version ==4 && cih->ihl >=5 ))return NF_ACCEPT ;/* The packet looks wrong, ignore */ raddr = (union nf_inet_addr *)&cih->daddr; + hlen_ipip = cih->ihl *4 ;/* Special case for errors for IPIP/UDP/GRE tunnel packets */ tunnel = false;
@@ -1649,9 +1651,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,/* Only for known tunnel */ if (!dest || dest->tun_type !=IP_VS_CONN_F_TUNNEL_TYPE_IPIP )return NF_ACCEPT ; - offset += cih->ihl *4 ; + offset += hlen_ipip; cih =skb_header_pointer (skb, offset,sizeof (_ciph), &_ciph); -if (cih ==NULL ) +if (!(cih && cih->version ==4 && cih->ihl >=5 ))return NF_ACCEPT ;/* The packet looks wrong, ignore */ tunnel = true; } else if ((cih->protocol == IPPROTO_UDP || /* Can be UDP encap */
@@ -1663,7 +1665,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,/* Non-first fragment has no UDP/GRE header */ if (unlikely (cih->frag_off &htons (IP_OFFSET )))return NF_ACCEPT ; - offset2 = offset + cih->ihl *4 ; + offset2 = offset + hlen_ipip;if (cih->protocol ==IPPROTO_UDP ) { ulen =ipvs_udp_decap (ipvs, skb, offset2,AF_INET , raddr, &iproto);
@@ -1732,6 +1734,7 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related, }if (tunnel) { +unsigned int hlen_orig = cih->ihl *4 ;__be32 info = ic->un.gateway;__u8 type = ic->type;__u8 code = ic->code;
@@ -1748,6 +1751,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related, goto ignore_tunnel; offset2 -= ihl +sizeof (_icmph);skb_reset_network_header (skb); +/* Ensure the IP header is present in headroom */ +if (!pskb_may_pull (skb, hlen_ipip)) + goto ignore_tunnel;IP_VS_DBG (12 ,"ICMP for %s %pI4->%pI4: mtu=%u\n" , outer_proto, &ip_hdr (skb)->saddr, &ip_hdr (skb)->daddr, mtu);
@@ -1763,8 +1769,8 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,if (dest_dst) mtu =dst_mtu (dest_dst->dst_cache); } -if (mtu >68 +sizeof (struct iphdr ) + ulen) - mtu -=sizeof (struct iphdr ) + ulen; +if (mtu >68 + hlen_ipip + ulen) + mtu -= hlen_ipip + ulen; info =htonl (mtu); }/* Strip outer IP, ICMP and IPIP/UDP/GRE, go to IP header of
@@ -1773,6 +1779,9 @@ ip_vs_in_icmp(struct netns_ipvs *ipvs, struct sk_buff *skb, int *related,if (pskb_pull (skb, offset2) ==NULL ) goto ignore_tunnel;skb_reset_network_header (skb); +/* Ensure the IP header is present in headroom */ +if (!pskb_may_pull (skb, hlen_orig)) + goto ignore_tunnel;IP_VS_DBG (12 ,"Sending ICMP for %pI4->%pI4: t=%u, c=%u, i=%u\n" , &ip_hdr (skb)->saddr, &ip_hdr (skb)->daddr, type, code,ntohl (info));
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 708/1067 cifs: validate DFS referral string offsets
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit 027a84ac6b50c12ef767c15abfc58aa865820e9e ]
parse_dfs_referrals() validates that the response header and referral array fit in the received buffer, but each referral also contains string offsets supplied by the server.
Those offsets are used to compute the DfsPath and NetworkAddress string pointers without checking whether they still point inside the response buffer. A malformed referral can therefore make the computed pointer exceed the end of the buffer. The resulting negative max_len is then passed to cifs_strndup_from_utf16(), and the non-Unicode path forwards it to kstrndup() as a size_t, allowing strnlen() to read out of bounds.
Validate each string offset before deriving the string pointer.
--- fs/smb/client/misc.c | 8 ++++++++ 1 file changed, 8 insertions(+)
fs/smb/client/misc.c +8 -0
@@ -981,6 +981,10 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, node->ref_flag =le16_to_cpu (ref->ReferralEntryFlags);/* copy DfsPath */ +if (le16_to_cpu (ref->DfsPathOffset) > data_end - (char *)ref) { + rc = -EINVAL ; + goto parse_DFS_referrals_exit; + } temp = (char *)ref +le16_to_cpu (ref->DfsPathOffset); max_len = data_end - temp; node->path_name = cifs_strndup_from_utf16(temp, max_len,
@@ -991,6 +995,10 @@ parse_dfs_referrals(struct get_dfs_referral_rsp *rsp, u32 rsp_size, }/* copy link target UNC */ +if (le16_to_cpu (ref->NetworkAddressOffset) > data_end - (char *)ref) { + rc = -EINVAL ; + goto parse_DFS_referrals_exit; + } temp = (char *)ref +le16_to_cpu (ref->NetworkAddressOffset); max_len = data_end - temp; node->node_name = cifs_strndup_from_utf16(temp, max_len,
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 709/1067 dm era: fix NULL pointer dereference in metadata_open()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cao Guanghui <[email protected]>
[ Upstream commit 9ae672606c17891d90b282e3490b817620549599 ]
metadata_open() returns NULL when kzalloc_obj() fails, but the caller era_ctr() only checks IS_ERR(md). Since IS_ERR(NULL) returns false, the NULL pointer is treated as a valid result and later assigned to era->md, leading to a NULL pointer dereference when the metadata is accessed.
Fix this by returning ERR_PTR(-ENOMEM) on allocation failure, consistent with dm-cache-metadata.c, dm-thin-metadata.c, and dm-clone-metadata.c which all use ERR_PTR(-ENOMEM) for the same pattern.
--- drivers/md/dm-era-target.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/md/dm-era-target.c +4 -2
@@ -795,8 +795,10 @@ static struct era_metadata *metadata_open(struct block_device *bdev,int r;struct era_metadata *md =kzalloc (sizeof (*md),GFP_KERNEL ); -if (!md) -return NULL ; +if (!md) { +DMERR ("could not allocate metadata struct" ); +return ERR_PTR (-ENOMEM ); + } md->bdev = bdev; md->block_size = block_size;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 710/1067 regulator: core: Make regulator_lock_two() logic easier to follow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Douglas Anderson <[email protected]>
[ Upstream commit 37473397b852f556d8b9428ccbfd51886037842d ]
The regulator_lock_two() function could be made clearer in the case of lock contention by having a local variable for each of the held and contended locks. Let's do that. At the same time, let's use the swap() function instead of open coding it.
This change is expected to be a no-op and simply improves code clarity.
Stable-dep-of: d38f8bd771c4 ("regulator: core: regulator_lock_two() should test for EDEADLK not EDEADLOCK")
--- drivers/regulator/core.c | 31 ++++++++++++------------------- 1 file changed, 12 insertions(+), 19 deletions(-)
drivers/regulator/core.c +12 -19
@@ -219,7 +219,7 @@ static void regulator_lock_two(struct regulator_dev *rdev1,struct regulator_dev *rdev2, struct ww_acquire_ctx *ww_ctx) { - struct regulator_dev *tmp; + struct regulator_dev *held, *contended;int ret;ww_acquire_init (ww_ctx, ®ulator_ww_class);
@@ -233,25 +233,18 @@ static void regulator_lock_two(struct regulator_dev *rdev1, goto exit; } + held = rdev1; + contended = rdev2;while (true) { -/* -* Start of loop: rdev1 was locked and rdev2 was contended. -* Need to unlock rdev1, slowly lock rdev2, then try rdev1 -* again. -*/ -regulator_unlock (rdev1); - -ww_mutex_lock_slow (&rdev2->mutex, ww_ctx); - rdev2->ref_cnt++; - rdev2->mutex_owner = current; - ret =regulator_lock_nested (rdev1, ww_ctx); - -if (ret == -EDEADLOCK ) { -/* More contention; swap which needs to be slow */ - tmp = rdev1; - rdev1 = rdev2; - rdev2 = tmp; - }else { +regulator_unlock (held); + +ww_mutex_lock_slow (&contended->mutex, ww_ctx); + contended->ref_cnt++; + contended->mutex_owner = current; +swap (held, contended); + ret =regulator_lock_nested (contended, ww_ctx); + +if (ret != -EDEADLOCK ) {WARN_ON (ret);break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 711/1067 regulator: core: regulator_lock_two() should test for EDEADLK not EDEADLOCK
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Timur Tabi <[email protected]>
[ Upstream commit d38f8bd771c4999b797d7074b348cf201414bd34 ]
Compare against -EDEADLK, which is what ww_mutex_lock() actually returns and what every other deadlock check in this file already uses.
Function regulator_lock_two() acquires two regulators via regulator_lock_nested() -> ww_mutex_lock(). On contention, ww_mutex_lock() returns -EDEADLK, which is the caller's signal to drop the lock it holds and retry the acquisition in the canonical order.
However, regulator_lock_two() tests the return value against -EDEADLOCK rather than -EDEADLK. On most architectures, EDEADLK and EDEADLOCK are the same value, so the comparison happens to be correct and the bug is invisible. But on MIPS, SPARC, and PowerPC, those two errors have different values. The test is wrong: a genuine -EDEADLK backoff no longer matches -EDEADLOCK, so instead of unlocking and retrying, the code falls into WARN_ON(ret) and returns with only one of the two regulators locked.
In practice, this is a bug only on MIPS, because the regulator core is not built or used on the other two platforms.
In general, EDEADLK is preferred over EDEADLOCK for new code.
--- drivers/regulator/core.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/regulator/core.c +2 -2
@@ -228,7 +228,7 @@ static void regulator_lock_two(struct regulator_dev *rdev1, ret =regulator_lock_nested (rdev1, ww_ctx);WARN_ON (ret); ret =regulator_lock_nested (rdev2, ww_ctx); -if (ret != -EDEADLOCK ) { +if (ret != -EDEADLK ) {WARN_ON (ret); goto exit; }
@@ -244,7 +244,7 @@ static void regulator_lock_two(struct regulator_dev *rdev1,swap (held, contended); ret =regulator_lock_nested (contended, ww_ctx); -if (ret != -EDEADLOCK ) { +if (ret != -EDEADLK ) {WARN_ON (ret);break ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 712/1067 net/mlx5: Fix L3 tunnel entropy refcount leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
[ Upstream commit c914307e1d41c2cb7bcdcbfde4cd2f214f6aa027 ]
mlx5_tun_entropy_refcount_inc() counts both VXLAN and L2-to-L3 tunnel reformat entries as entropy-enabling users. The matching decrement path only handled VXLAN, leaving L2-to-L3 tunnel entries counted after release.
Handle MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL in mlx5_tun_entropy_refcount_dec() as well so the enabling entry refcount remains balanced.
--- drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/ethernet/mellanox/mlx5/core/lib/port_tun.c +2 -1
@@ -176,7 +176,8 @@ void mlx5_tun_entropy_refcount_dec(struct mlx5_tun_entropy *tun_entropy, int reformat_type) {mutex_lock (&tun_entropy->lock); -if (reformat_type ==MLX5_REFORMAT_TYPE_L2_TO_VXLAN ) +if (reformat_type ==MLX5_REFORMAT_TYPE_L2_TO_VXLAN || + reformat_type ==MLX5_REFORMAT_TYPE_L2_TO_L3_TUNNEL ) tun_entropy->num_enabling_entries--;else if (reformat_type ==MLX5_REFORMAT_TYPE_L2_TO_NVGRE && --tun_entropy->num_disabling_entries ==0 )
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 713/1067 octeontx2-af: fix VF bringup affecting PF promiscuous state
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Harman Kalra <[email protected]>
[ Upstream commit fabb881df322da25442f98d23f5fa371e3c78ec4 ]
Mbox handling of nix_set_rx_mode for a VF with promiscuous and all_multi flags set to false causes deletion of the PF's promiscuous and allmulti MCAM rules. This occurs because the APIs that enable/disable these rules operate only on the PF, even when the mbox request is made via a VF interface.
Guard both rvu_npc_enable_allmulti_entry() and rvu_npc_enable_promisc_entry() disable paths with an is_vf() check so that a VF bringing up or tearing down its interface cannot inadvertently clear the PF's MCAM rules.
--- drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/net/ethernet/marvell/octeontx2/af/rvu_nix.c +2 -2
@@ -4084,7 +4084,7 @@ int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req,rvu_npc_install_allmulti_entry (rvu, pcifunc, nixlf, pfvf->rx_chan_base); }else { -if (!nix_rx_multicast) +if (!nix_rx_multicast && !is_vf (pcifunc))rvu_npc_enable_allmulti_entry (rvu, pcifunc, nixlf, false); }
@@ -4094,7 +4094,7 @@ int rvu_mbox_handler_nix_set_rx_mode(struct rvu *rvu, struct nix_rx_mode *req, pfvf->rx_chan_base, pfvf->rx_chan_cnt); else - if (!nix_rx_multicast) + if (!nix_rx_multicast && !is_vf(pcifunc))rvu_npc_enable_promisc_entry (rvu, pcifunc, nixlf, false);return 0 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 714/1067 smb: client: fix overflow in passthrough ioctl bounds check
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
[ Upstream commit a4f27ad055392fa164f5649e89a3637b033c5fcc ]
smb2_ioctl_query_info() validates the PASSTHRU_FSCTL response payload before copying it to userspace.
The payload offset and length both come from 32-bit fields. The bounds check currently adds OutputOffset and qi.input_buffer_length directly, so the addition can wrap in 32-bit arithmetic before the result is compared against the response buffer length.
A malicious server can use a large OutputOffset and a small OutputCount to make the wrapped sum pass the bounds check. The later copy_to_user() then reads from io_rsp + OutputOffset, outside the response buffer.
Use size_add() for the offset plus length check so overflow is treated as out of bounds.
--- fs/smb/client/smb2ops.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
fs/smb/client/smb2ops.c +2 -2
@@ -1690,8 +1690,8 @@ smb2_ioctl_query_info(const unsigned int xid,if (le32_to_cpu (io_rsp->OutputCount) < qi.input_buffer_length) qi.input_buffer_length =le32_to_cpu (io_rsp->OutputCount);if (qi.input_buffer_length >0 && -le32_to_cpu (io_rsp->OutputOffset) + qi.input_buffer_length - > rsp_iov[1 ].iov_len) { +size_add (le32_to_cpu (io_rsp->OutputOffset), + qi.input_buffer_length) > rsp_iov[1 ].iov_len) { rc = -EFAULT ; goto out; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 715/1067 mlxsw: fix refcount leak in mlxsw_sp_vrs_lpm_tree_replace()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wentao Liang <[email protected]>
commit 21cf8dc478a49e8de039c2739b1646a774cb1944 upstream.
When mlxsw_sp_vrs_lpm_tree_replace() fails after replacing some VRs, the error rollback loop does not correctly revert the preceding replacements. The loop decrements the index but fails to update the vr pointer, which still points to the VR that caused the failure. As a result, the condition and the rollback call always operate on the same VR, potentially calling mlxsw_sp_vr_lpm_tree_replace() multiple times on it while never rolling back the earlier VRs. Those VRs continue to hold a reference to new_tree acquired via mlxsw_sp_lpm_tree_hold(), leaking the reference count of new_tree.
Fix by reinitializing vr inside the error loop with the updated index:
vr = &mlxsw_sp->router->vrs[i];
so that the loop correctly iterates over all VRs that were actually replaced.
--- drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/ethernet/mellanox/mlxsw/spectrum_router.c +1 -0
@@ -986,6 +986,7 @@ static int mlxsw_sp_vrs_lpm_tree_replace err_tree_replace:for (i--; i >=0 ; i--) { + vr = &mlxsw_sp->router->vrs[i];if (!mlxsw_sp_vr_lpm_tree_should_replace (vr, proto, new_id))continue ; mlxsw_sp_vr_lpm_tree_replace(mlxsw_sp,
Greg Kroah-Hartman
maintainerPATCH 716/1067 vduse: Fix race in vduse_dev_msg_sync and vduse_dev_read_iter
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhang Tianci <[email protected]>
commit ae9c13b6fd79087cc5a216ee1649b6f012c2a238 upstream.
There is one race case in vduse_dev_msg_sync and vduse_dev_read_iter:
vduse_dev_read_iter():
lock(msg_lock);
dequeue_msg(send_list);
unlock(msg_lock);
vduse_dev_msg_sync():
wait_timeout() finish
lock(msg_lock);
check msg->complete is false
list_del(msg); <- double list_del() crash!To fix this case, we shall ensure vduse_msg is on send_list or recv_list outside the msg_lock critical section.
Message-ID: <[email protected]>
--- drivers/vdpa/vdpa_user/vduse_dev.c | 37 +++++++++++++++++++++++++++---------- 1 file changed, 27 insertions(+), 10 deletions(-)
drivers/vdpa/vdpa_user/vduse_dev.c +27 -10
@@ -319,6 +319,7 @@ static ssize_t vduse_dev_read_iter(strucstruct file *file = iocb->ki_filp;struct vduse_dev *dev = file->private_data;struct vduse_dev_msg *msg; +struct vduse_dev_request req;int size =sizeof (struct vduse_dev_request );ssize_t ret;
@@ -330,12 +331,11 @@ static ssize_t vduse_dev_read_iter(struc msg =vduse_dequeue_msg (&dev->send_list);if (msg)break ; +spin_unlock (&dev->msg_lock); - ret = -EAGAIN ;if (file->f_flags &O_NONBLOCK ) - goto unlock; +return -EAGAIN ; -spin_unlock (&dev->msg_lock); ret =wait_event_interruptible_exclusive (dev->waitq, !list_empty (&dev->send_list));if (ret)
@@ -343,17 +343,34 @@ static ssize_t vduse_dev_read_iter(strucspin_lock (&dev->msg_lock); } + +memcpy (&req, &msg->req,sizeof (req)); +/* +* We must ensure vduse_msg is on send_list or recv_list before unlock +* dev->msg_lock. Because vduse_dev_msg_sync() may be timeout when we +* copy data to userspace, and will call list_del() for this msg. +*/ +vduse_enqueue_msg (&dev->recv_list, msg);spin_unlock (&dev->msg_lock); - ret =copy_to_iter (&msg->req, size, to); -spin_lock (&dev->msg_lock); + + ret =copy_to_iter (&req, size, to);if (ret != size) { +/* +* Roll back: move msg back to send_list if still pending. +* +* NOTE: +* vduse_find_msg() must use req.request_id instead of `msg`. +* A malicious userspace may reply to this request, and wake up +* the caller, after which `msg` will have already been freed. +* And here vduse_find_msg() will return NULL then do nothing. +*/ +spin_lock (&dev->msg_lock); + msg =vduse_find_msg (&dev->recv_list, req.request_id); +if (msg) +vduse_enqueue_msg_head (&dev->send_list, msg); +spin_unlock (&dev->msg_lock); ret = -EFAULT ; -vduse_enqueue_msg_head (&dev->send_list, msg); - goto unlock; } -vduse_enqueue_msg (&dev->recv_list, msg); -unlock: -spin_unlock (&dev->msg_lock);return ret; }
Greg Kroah-Hartman
maintainerPATCH 717/1067 ASoC: SOF: ipc3-control: Use overflow checks in control_update size calc
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit 8791977d7289f6e9d2b014f60a5455f053a7bc04 upstream.
In sof_ipc3_control_update(), the expected_size calculation uses firmware-provided cdata->num_elems in arithmetic that could overflow on 32-bit platforms, wrapping to a small value. This would allow the cdata->rhdr.hdr.size comparison to pass with mismatched sizes, potentially leading to out-of-bounds access in snd_sof_update_control.
Use check_mul_overflow() and check_add_overflow() to detect and reject overflowed size calculations.
--- sound/soc/sof/ipc3-control.c | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-)
sound/soc/sof/ipc3-control.c +16 -4
@@ -604,16 +604,28 @@ static void sof_ipc3_control_update(strureturn ; } - expected_size =sizeof (struct sof_ipc_ctrl_data );switch (cdata->type) {case SOF_CTRL_TYPE_VALUE_CHAN_GET :case SOF_CTRL_TYPE_VALUE_CHAN_SET : - expected_size += cdata->num_elems * -sizeof (struct sof_ipc_ctrl_value_chan ); +if (check_mul_overflow ((size_t )cdata->num_elems, +sizeof (struct sof_ipc_ctrl_value_chan ), + &expected_size)) +return ; +if (check_add_overflow (expected_size, +sizeof (struct sof_ipc_ctrl_data ), + &expected_size)) +return ;break ;case SOF_CTRL_TYPE_DATA_GET :case SOF_CTRL_TYPE_DATA_SET : - expected_size += cdata->num_elems +sizeof (struct sof_abi_hdr ); +if (check_add_overflow ((size_t )cdata->num_elems, +sizeof (struct sof_abi_hdr ), + &expected_size)) +return ; +if (check_add_overflow (expected_size, +sizeof (struct sof_ipc_ctrl_data ), + &expected_size)) +return ;break ;default :return ;
Greg Kroah-Hartman
maintainerPATCH 718/1067 ASoC: SOF: ipc3-control: Fix TOCTOU in bytes_put and bytes_get
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit 1f97760417b5faa60e9642fd0ed61eb17d0b1b39 upstream.
In sof_ipc3_bytes_put(), the size used for the memcpy is derived from the old data->size already in the buffer, not the incoming new data's size field. If the new data has a different size, the copy length is
wrong: it may truncate valid data or copy stale bytes.
Similarly, sof_ipc3_bytes_get() checks data->size against max_size without accounting for the sizeof(struct sof_ipc_ctrl_data) offset of the flex array within the allocation.
Fix bytes_put to validate and use the incoming data's sof_abi_hdr.size from ucontrol before copying. Fix bytes_get to subtract sizeof(*cdata) from the bounds check to match the actual available space.
--- sound/soc/sof/ipc3-control.c | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-)
sound/soc/sof/ipc3-control.c +16 -7
@@ -281,10 +281,13 @@ static int sof_ipc3_bytes_get(struct snd }/* be->max has been verified to be >= sizeof(struct sof_abi_hdr) */ -if (data->size > scontrol->max_size -sizeof (*data)) { +if (data->size > scontrol->max_size -sizeof (*cdata) - +sizeof (*data)) {dev_err_ratelimited (scomp->dev,"%u bytes of control data is invalid, max is %zu\n" , - data->size, scontrol->max_size -sizeof (*data)); + data->size, + scontrol->max_size -sizeof (*cdata) - +sizeof (*data));return -EINVAL ; }
@@ -302,6 +305,8 @@ static int sof_ipc3_bytes_put(struct sndstruct sof_ipc_ctrl_data *cdata = scontrol->ipc_control_data;struct snd_soc_component *scomp = scontrol->scomp;struct sof_abi_hdr *data = cdata->data; +const struct sof_abi_hdr *new_hdr = + (const struct sof_abi_hdr *)ucontrol->value.bytes.data;size_t size;if (scontrol->max_size >sizeof (ucontrol->value.bytes.data)) {
@@ -310,14 +315,18 @@ static int sof_ipc3_bytes_put(struct sndreturn -EINVAL ; } -/* scontrol->max_size has been verified to be >= sizeof(struct sof_abi_hdr) */ -if (data->size > scontrol->max_size -sizeof (*data)) { -dev_err_ratelimited (scomp->dev,"data size too big %u bytes max is %zu\n" , - data->size, scontrol->max_size -sizeof (*data)); +/* Validate the new data's size, not the old one */ +if (new_hdr->size > scontrol->max_size -sizeof (*cdata) - +sizeof (*new_hdr)) { +dev_err_ratelimited (scomp->dev, +"data size too big %u bytes max is %zu\n" , + new_hdr->size, + scontrol->max_size -sizeof (*cdata) - +sizeof (*new_hdr));return -EINVAL ; } - size = data->size +sizeof (*data); + size = new_hdr->size +sizeof (*new_hdr);/* copy from kcontrol */ memcpy (data, ucontrol->value.bytes.data, size);
Greg Kroah-Hartman
maintainerPATCH 719/1067 net: qrtr: fix 32-bit integer overflow in qrtr_endpoint_post()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 20054869770c7df060c5ecee3e8bbf9029c47191 upstream.
qrtr_endpoint_post() validates an incoming packet with
if (!size || len != ALIGN(size, 4) + hdrlen) goto err;
where size comes from the wire. On 32-bit, size_t is 32 bits and ALIGN(size, 4) wraps to 0 for size >= 0xfffffffd, so the check passes and skb_put_data(skb, data + hdrlen, size) writes past the hdrlen-sized skb and oopses the kernel. 64-bit is unaffected.
This is the 32-bit residual of ad9d24c9429e2 ("net: qrtr: fix OOB Read in qrtr_endpoint_post"), which fixed only the 64-bit case.
Reject any size that cannot fit the buffer before the ALIGN.
--- net/qrtr/af_qrtr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/qrtr/af_qrtr.c +1 -1
@@ -491,7 +491,7 @@ int qrtr_endpoint_post(struct qrtr_endpo goto err; } -if (!size || len !=ALIGN (size,4 ) + hdrlen) +if (!size || size > len || len !=ALIGN (size,4 ) + hdrlen) goto err; if ((cb->type == QRTR_TYPE_NEW_SERVER ||
Greg Kroah-Hartman
maintainerPATCH 720/1067 net: atm: reject out-of-range traffic classes in QoS validation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhengchuan Liang <[email protected]>
commit cdf19f380e46192e7084be559638aab1f6ed86a2 upstream.
Reject ATM traffic classes above ATM_ANYCLASS in check_tp(). SO_ATMQOS stores the supplied QoS after check_qos() succeeds, so accepting larger values leaves invalid traffic_class values in vcc->qos.
That bad state later reaches pvc_info(), which indexes class_name[] with vcc->qos.{rx,tp}.traffic_class. Values above ATM_ANYCLASS cause an out-of-bounds read when /proc/net/atm/pvc is read.
Tighten the existing QoS validation so invalid traffic_class values are rejected at the point where user supplied QoS is accepted.
--- net/atm/common.c | 2 ++ 1 file changed, 2 insertions(+)
net/atm/common.c +2 -0
@@ -720,6 +720,8 @@ static int atm_change_qos(struct atm_vccstatic int check_tp (const struct atm_trafprm *tp) {/* @@@ Should be merged with adjust_tp */ +if (tp->traffic_class >ATM_ANYCLASS ) +return -EINVAL ;if (!tp->traffic_class || tp->traffic_class ==ATM_ANYCLASS )return 0 ; if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
Greg Kroah-Hartman
maintainerPATCH 721/1067 net: ife: require ETH_HLEN to be pullable in ife_decode()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yong Wang <[email protected]>
commit 9406f6012b7343661efb516a11c62d4db2b62f75 upstream.
ife decode may return after making only the outer IFE header and metadata pullable. The caller then passes the decapsulated packet to eth_type_trans(), which expects the inner Ethernet header to be accessible from the linear data area.
With a malformed IFE frame, the inner Ethernet header may still be shorter than ETH_HLEN in the linear area, which can lead to a crash in the original code.
Fix this by extending the pull check in ife_decode() so that the inner Ethernet header is also guaranteed to be pullable before returning.
--- net/ife/ife.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/ife/ife.c +1 -1
@@ -79,7 +79,7 @@ void *ife_decode(struct sk_buff *skb, u1if (unlikely (ifehdrln <2 ))return NULL ; -if (unlikely (!pskb_may_pull (skb, total_pull))) +if (unlikely (!pskb_may_pull (skb, total_pull +ETH_HLEN )))return NULL ; ifehdr = (struct ifeheadr *)(skb->data + skb->dev->hard_header_len);
Greg Kroah-Hartman
maintainerPATCH 722/1067 arm64: fpsimd: Fix type mismatch in sve_{save,load}_state()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mark Rutland <[email protected]>
commit ae24f6b06e90681ec36b9c21c3f5c09618350f5a upstream.
The sve_save_state() and sve_load_state() functions take a 32-bit int argument that describes whether to save/restore the FFR. Their assembly implementations consume the entire 64-bit register containing this 32-bit value, and will attempt to save/restore the FFR if any bit of that 64-bit register is non-zero.
Per the AAPCS64 parameter passing rules, the callee is responsible for any necessary widening, and the upper 32-bits are permitted to contain arbitrary values. If the upper 32 bits are non-zero, this could result in an unexpected attempt to save/restore the FFR, and consequently could lead to unexpected traps/undefs/faults.
In practice compilers are very unlikely to generate code where the upper 32-bits would be non-zero, but they are permitted to do so.
Fix this by only consuming the low 32 bits of the register, and update comments accordingly.
The hyp code __sve_save_state() and __sve_restore_state() functions don't have the same latent bug as they override the full 64-bit register containing the argument.
--- arch/arm64/kernel/entry-fpsimd.S | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
arch/arm64/kernel/entry-fpsimd.S +4 -4
@@ -38,10 +38,10 @@ SYM_FUNC_END(fpsimd_load_state) * * x0 - pointer to buffer for state * x1 - pointer to storage for FPSR - * x2 - Save FFR if non-zero + * w2 - Save FFR if non-zero */ SYM_FUNC_START(sve_save_state) - sve_save 0, x1, x2, 3 + sve_save 0, x1, w2, 3 ret SYM_FUNC_END(sve_save_state)
@@ -50,10 +50,10 @@ SYM_FUNC_END(sve_save_state) * * x0 - pointer to buffer for state * x1 - pointer to storage for FPSR - * x2 - Restore FFR if non-zero + * w2 - Restore FFR if non-zero */ SYM_FUNC_START(sve_load_state) - sve_load 0, x1, x2, 4 + sve_load 0, x1, w2, 4 ret SYM_FUNC_END(sve_load_state)
Greg Kroah-Hartman
maintainerPATCH 723/1067 arm64: dts: qcom: sdm630: describe adsp_mem region properly
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nickolay Goppen <[email protected]>
commit ce414263e9ebe5080381a50cbdf9065c29816202 upstream.
Downstream [1] this region is marked as shared, reusable and dynamic so describe it that way.
--- arch/arm64/boot/dts/qcom/sdm630.dtsi | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
arch/arm64/boot/dts/qcom/sdm630.dtsi +6 -3
@@ -402,9 +402,12 @@ no-map; }; - adsp_mem: adsp-region@f6000000 { - reg = <0x0 0xf6000000 0x0 0x800000>; - no-map; + adsp_mem: adsp-region { + compatible = "shared-dma-pool"; + alloc-ranges = <0x0 0x80000000 0x0 0x80000000>; + alignment = <0x0 0x400000>; + size = <0x0 0x800000>; + reusable; }; qseecom_mem: qseecom-region@f6800000 {
Greg Kroah-Hartman
maintainerPATCH 724/1067 KVM: s390: pci: Fix GISC refcount leak on AIF enable failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 7b69729046a4c58f4cb457184e5ac4aaa179bff4 upstream.
kvm_s390_gisc_register() registers the guest ISC before pinning the guest interrupt forwarding pages and allocating the AISB bit. If any of the later setup steps fails, the function unwinds the pinned pages and other local state, but does not unregister the GISC reference. Add the missing kvm_s390_gisc_unregister() to the error unwind path.
Message-ID: <[email protected]>
--- arch/s390/kvm/pci.c | 1 + 1 file changed, 1 insertion(+)
arch/s390/kvm/pci.c +1 -0
@@ -330,6 +330,7 @@ unpin2: unpin1:unpin_user_page (aibv_page); out: +kvm_s390_gisc_unregister (kvm, fib->fmt0.isc);return rc; }
Greg Kroah-Hartman
maintainerPATCH 725/1067 KVM: arm64: vgic: Check the interrupt is still ours before migrating it
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
commit 0074b82cdfcb5fd13710a0ac308ade68ac6f6fbe upstream.
vgic_prune_ap_list() drops both ap_list_lock and irq_lock while migrating an interrupt to another vCPU. After reacquiring the locks it only checks that the affinity is unchanged (target_vcpu == vgic_target_oracle(irq)) before moving the interrupt, which assumes that an interrupt whose affinity is preserved is still queued on this vCPU's ap_list.
That assumption no longer holds if the interrupt is taken off the ap_list while the locks are dropped. vgic_flush_pending_lpis() removes the interrupt from the list and sets irq->vcpu to NULL, but leaves enabled/pending/target_vcpu untouched. As the interrupt is still enabled and pending, vgic_target_oracle() returns the same target_vcpu, so the affinity check passes and list_del() is run a second time on an entry that has already been removed.
Also check that the interrupt is still assigned to this vCPU (irq->vcpu == vcpu) before moving it.
--- arch/arm64/kvm/vgic/vgic.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
arch/arm64/kvm/vgic/vgic.c +6 -5
@@ -686,15 +686,16 @@ retry:raw_spin_lock (&irq->irq_lock);/* -* If the affinity has been preserved, move the -* interrupt around. Otherwise, it means things have -* changed while the interrupt was unlocked, and we -* need to replay this. +* If the interrupt is still ours and its affinity has +* been preserved, move it around. Otherwise, it means +* things have changed while the interrupt was unlocked +* (it may even have been taken off the list with its +* affinity left untouched), and we need to replay this. * * In all cases, we cannot trust the list not to have * changed, so we restart from the beginning. */ -if (target_vcpu ==vgic_target_oracle (irq)) { +if (irq->vcpu == vcpu && target_vcpu ==vgic_target_oracle (irq)) {struct vgic_cpu *new_cpu = &target_vcpu->arch.vgic_cpu;list_del (&irq->ap_list);
Greg Kroah-Hartman
maintainerPATCH 726/1067 KVM: s390: pci: Fix handling of AIF enable without AISB
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew Rosato <[email protected]>
commit 3e3aa6da87d30a0064a17b836685cd43c90a3572 upstream.
When a guest seeks to register IRQs without a summary bit specified, ensure that the associated GAITE then stores 0 for the guest AISB location instead of virt_to_phys(page_address(NULL)).
--- arch/s390/kvm/pci.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
arch/s390/kvm/pci.c +8 -3
@@ -302,9 +302,14 @@ static int kvm_s390_pci_aif_enable(struc gaite->gisc = fib->fmt0.isc; gaite->count++; - gaite->aisbo = fib->fmt0.aisbo; - gaite->aisb =virt_to_phys (page_address (aisb_page) + (fib->fmt0.aisb & - ~PAGE_MASK )); +if (fib->fmt0.sum ==1 ) { + gaite->aisbo = fib->fmt0.aisbo; + gaite->aisb =virt_to_phys (page_address (aisb_page) + + (fib->fmt0.aisb & ~PAGE_MASK )); + }else { + gaite->aisbo =0 ; + gaite->aisb =0 ; + } aift->kzdev[zdev->aisb] = zdev->kzdev;spin_unlock_irq (&aift->gait_lock);
Greg Kroah-Hartman
maintainerPATCH 727/1067 KVM: x86: Ignore pending PV EOI if the vCPU has since disabled PV EOIs
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 9285e4070df2c40585c3d7ec9571faa7a2b97e17 upstream.
Ignore KVM's internal "service pending PV EOI" request if the vCPU has disabled PV EOIs since the request was made. Asserting that PV EOIs are enabled can fail if reading guest memory in pv_eoi_get_user() fails, i.e. if pv_eoi_test_and_clr_pending() bails early, *and* the vCPU also disables PV EOIs.
kernel BUG at arch/x86/kvm/lapic.c:3338!
Oops: invalid opcode: 0000 [#1] SMP CPU: 4 UID: 1000 PID: 890 Comm: pv_eoi_test Not tainted 7.0.0-d585aa5894d8-vm #337 PREEMPT Hardware name: QEMU Standard PC (Q35 + ICH9, 2009), BIOS 0.0.0 02/06/2015 RIP: 0010:kvm_lapic_sync_from_vapic+0x12b/0x140 [kvm] Call Trace: <TASK> kvm_arch_vcpu_ioctl_run+0x1075/0x1c30 [kvm] kvm_vcpu_ioctl+0x2d5/0x980 [kvm] __x64_sys_ioctl+0x8a/0xd0 do_syscall_64+0xb5/0xb40 entry_SYSCALL_64_after_hwframe+0x4b/0x53 </TASK> Modules linked in: kvm_intel kvm irqbypass ---[ end trace 0000000000000000 ]---
--- arch/x86/kvm/lapic.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
arch/x86/kvm/lapic.c +6 -2
@@ -2913,6 +2913,12 @@ static void apic_sync_pv_eoi_from_guest( struct kvm_lapic *apic) {int vector; + +if (unlikely (!pv_eoi_enabled (vcpu))) { +__clear_bit (KVM_APIC_PV_EOI_PENDING , &vcpu->arch.apic_attention); +return ; + } +/* * PV EOI state is derived from KVM_APIC_PV_EOI_PENDING in host * and KVM_PV_EOI_ENABLED in guest memory as follows:
@@ -2924,8 +2930,6 @@ static void apic_sync_pv_eoi_from_guest(* KVM_APIC_PV_EOI_PENDING is set, KVM_PV_EOI_ENABLED is unset: * -> host enabled PV EOI, guest executed EOI. */ -BUG_ON (!pv_eoi_enabled (vcpu)); -if (pv_eoi_test_and_clr_pending (vcpu))return ; vector =apic_set_eoi (apic);
Greg Kroah-Hartman
maintainerPATCH 728/1067 fbdev: metronomefb: fix potential memory leak in metronomefb_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 894632b862a39b3fe1cb5de06fbae86225ea64de upstream.
The memory allocated for pagerefs in fb_deferred_io_init() is not freed on the error path. Fix it by calling fb_deferred_io_cleanup().
--- drivers/video/fbdev/metronomefb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/video/fbdev/metronomefb.c +6 -2
@@ -703,12 +703,14 @@ static int metronomefb_probe(struct plat info->flags =FBINFO_FLAG_DEFAULT |FBINFO_VIRTFB ; info->fbdefio = &metronomefb_defio; -fb_deferred_io_init (info); + retval =fb_deferred_io_init (info); +if (retval) + goto err_free_irq; retval =fb_alloc_cmap (&info->cmap,8 ,0 );if (retval <0 ) {dev_err (&dev->dev,"Failed to allocate colormap\n" ); - goto err_free_irq; + goto err_fbdefio; }/* set cmap */
@@ -731,6 +733,8 @@ static int metronomefb_probe(struct plat err_cmap:fb_dealloc_cmap (&info->cmap); +err_fbdefio: +fb_deferred_io_cleanup (info); err_free_irq: board->cleanup (par); err_csum_table:
Greg Kroah-Hartman
maintainerPATCH 729/1067 fbdev: broadsheetfb: fix potential memory leak in broadsheetfb_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 9d18a4e4234fd3ee0d0eed8ccbbb50cb76b2232c upstream.
The memory allocated for pagerefs in fb_deferred_io_init() is not freed on the error path. Fix it by calling fb_deferred_io_cleanup().
--- drivers/video/fbdev/broadsheetfb.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
drivers/video/fbdev/broadsheetfb.c +6 -2
@@ -1134,12 +1134,14 @@ static int broadsheetfb_probe(struct pla info->flags =FBINFO_FLAG_DEFAULT |FBINFO_VIRTFB ; info->fbdefio = &broadsheetfb_defio; -fb_deferred_io_init (info); + retval =fb_deferred_io_init (info); +if (retval) + goto err_vfree; retval =fb_alloc_cmap (&info->cmap,16 ,0 );if (retval <0 ) {dev_err (&dev->dev,"Failed to allocate colormap\n" ); - goto err_vfree; + goto err_fbdefio; }/* set cmap */
@@ -1183,6 +1185,8 @@ err_free_irq: board->cleanup (par); err_cmap:fb_dealloc_cmap (&info->cmap); +err_fbdefio: +fb_deferred_io_cleanup (info); err_vfree:vfree (videomemory); err_fb_rel:
Greg Kroah-Hartman
maintainerPATCH 730/1067 fbdev: hecubafb: fix potential memory leak in hecubafb_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit cbef2a305a8a72969b86f96b7c07b86edde61aff upstream.
The memory allocated for pagerefs in fb_deferred_io_init() is not freed on the error path. Fix it by calling fb_deferred_io_cleanup().
--- drivers/video/fbdev/hecubafb.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
drivers/video/fbdev/hecubafb.c +5 -1
@@ -254,7 +254,9 @@ static int hecubafb_probe(struct platfor info->flags =FBINFO_FLAG_DEFAULT |FBINFO_VIRTFB ; info->fbdefio = &hecubafb_defio; -fb_deferred_io_init (info); + retval =fb_deferred_io_init (info); +if (retval) + goto err_fbdefio; retval =register_framebuffer (info);if (retval <0 )
@@ -271,6 +273,8 @@ static int hecubafb_probe(struct platforreturn 0 ; err_fbreg: +fb_deferred_io_cleanup (info); +err_fbdefio:framebuffer_release (info); err_fballoc:vfree (videomemory);
Greg Kroah-Hartman
maintainerPATCH 731/1067 fbdev: sm712: Fix operator precedence in big_swap macro
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Li RongQing <[email protected]>
commit 5dbe5b65df0b0c0ec77492427c274b7b5011890e upstream.
The big_swap(p) macro was intended to swap bytes within 16-bit halves of a 32-bit value. However, because the bitwise shift operators (<<, >>) have higher precedence than the bitwise AND operator (&), the original code failed to perform any shifting on the masked bits.
For example, 'p & 0xff00ff00 >> 8' was evaluated as 'p & (0xff00ff00 >> 8)', effectively neutralizing the intended swap.
Fix this by adding parentheses to ensure the bitwise AND is performed before the shift, correctly implementing the byte swap logic.
--- drivers/video/fbdev/sm712.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/video/fbdev/sm712.h +1 -1
@@ -101,7 +101,7 @@ struct modeinit {#define mmio_addr 0x00800000#define seqw17 () smtc_seqw(0x17, 0x30)#define big_pixel_depth (p, d) {if (p == 24) {p = 32; d = 32; } } -#define big_swap (p) ((p & 0xff00ff00 >> 8) | (p & 0x00ff00ff << 8)) +#define big_swap (p) (((p & 0xff00ff00) >> 8) | ((p & 0x00ff00ff) << 8))#else #define pal_rgb (r, g, b, val) val#define big_addr 0
Greg Kroah-Hartman
maintainerPATCH 732/1067 fbdev: radeon: fix potential memory leak in radeonfb_pci_register()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit df8c1101c9a08859da612b5d0a08d55d475522c6 upstream.
The function radeonfb_pci_register() allocates memory for modelist (by calling radeon_check_modes() which calls fb_add_videomode()). The memory is appended to info->modelist, but is not freed in subsequent error paths. Fix this by calling fb_destroy_modelist().
--- drivers/video/fbdev/aty/radeon_base.c | 1 + 1 file changed, 1 insertion(+)
drivers/video/fbdev/aty/radeon_base.c +1 -0
@@ -2475,6 +2475,7 @@ static int radeonfb_pci_register(structreturn 0 ; err_unmap_fb:iounmap (rinfo->fb_base); +fb_destroy_modelist (&info->modelist); err_unmap_rom:kfree (rinfo->mon1_EDID);kfree (rinfo->mon2_EDID);
Greg Kroah-Hartman
maintainerPATCH 733/1067 fbdev: i740fb: fix potential memory leak in i740fb_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 5936063409af230a2c88b8700c47b89a19fd70b5 upstream.
In i740fb_probe(), the memory allocated in fb_videomode_to_modelist() for modelist is not freed in the error paths. Fix that by calling fb_destroy_modelist().
--- drivers/video/fbdev/i740fb.c | 1 + 1 file changed, 1 insertion(+)
drivers/video/fbdev/i740fb.c +1 -0
@@ -1155,6 +1155,7 @@ err_reg_framebuffer:fb_dealloc_cmap (&info->cmap); err_alloc_cmap: err_find_mode: +fb_destroy_modelist (&info->modelist);if (par->ddc_registered)i2c_del_adapter (&par->ddc_adapter);pci_iounmap (dev, par->regs);
Greg Kroah-Hartman
maintainerPATCH 734/1067 fbdev: s3fb: fix potential memory leak in s3_pci_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 3b0ed04bc852887a9164e1bbf521652e8ef3eb92 upstream.
In s3_pci_probe(), the memory allocated for modelist using fb_videomode_to_modelist() is not freed in subsequent error paths. Fix that by calling fb_destroy_modelist()
--- drivers/video/fbdev/s3fb.c | 1 + 1 file changed, 1 insertion(+)
drivers/video/fbdev/s3fb.c +1 -0
@@ -1374,6 +1374,7 @@ err_reg_fb: err_alloc_cmap: err_find_mode:#ifdef CONFIG_FB_S3_DDC +fb_destroy_modelist (&info->modelist);if (par->ddc_registered)i2c_del_adapter (&par->ddc_adapter);if (par->mmio)
Greg Kroah-Hartman
maintainerPATCH 735/1067 fbdev: uvesafb: fix potential memory leak in uvesafb_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 033e56fed09047ee63072e9f58789f40c1c7079d upstream.
Due to an incorrect goto label, memory allocated for modedb and modelist in uvesafb_vbe_init() is not freed in some error paths. Fix this by updating the goto label.
--- drivers/video/fbdev/uvesafb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/video/fbdev/uvesafb.c +2 -2
@@ -1700,14 +1700,14 @@ static int uvesafb_probe(struct platform i =uvesafb_vbe_init_mode (info);if (i <0 ) { err = -EINVAL ; - goto out; + goto out_mode; }else { mode = &par->vbe_modes[i]; }if (fb_alloc_cmap (&info->cmap,256 ,0 ) <0 ) { err = -ENXIO ; - goto out; + goto out_mode; }uvesafb_init_info (info, mode);
Greg Kroah-Hartman
maintainerPATCH 736/1067 fbdev: tdfxfb: fix potential memory leak in tdfxfb_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit bb019d755366cc3e777a12d4bf457ff289837370 upstream.
In tdfxfb_probe(), the memory allocated for modelist using fb_videomode_to_modelist() when CONFIG_FB_3DFX_I2C is defined, is not freed in the subsequent error paths.
Fix that by calling fb_destroy_modelist().
--- drivers/video/fbdev/tdfxfb.c | 1 + 1 file changed, 1 insertion(+)
drivers/video/fbdev/tdfxfb.c +1 -0
@@ -1551,6 +1551,7 @@ static int tdfxfb_probe(struct pci_dev * out_err_iobase:#ifdef CONFIG_FB_3DFX_I2C +fb_destroy_modelist (&info->modelist);tdfxfb_delete_i2c_busses (default_par);#endif arch_phys_wc_del (default_par->wc_cookie);
Greg Kroah-Hartman
maintainerPATCH 737/1067 fbdev: carminefb: fix potential memory leak in alloc_carmine_fb()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 6fcca16a2b19c37f60693c56cbc0c923364ff3ef upstream.
The memory allocated for modelist in fb_videomode_to_modelist() is not freed in the subsequent error path.
Fix that by calling fb_destroy_modelist()
--- drivers/video/fbdev/carminefb.c | 1 + 1 file changed, 1 insertion(+)
drivers/video/fbdev/carminefb.c +1 -0
@@ -593,6 +593,7 @@ static int alloc_carmine_fb(void __iomemreturn 0 ; err_dealloc_cmap: +fb_destroy_modelist (&info->modelist);fb_dealloc_cmap (&info->cmap); err_free_fb:framebuffer_release (info);
Greg Kroah-Hartman
maintainerPATCH 738/1067 fbdev: nvidia: fix potential memory leak in nvidiafb_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 85f5e38c162bdf9dbbe197275d416402712f3707 upstream.
In nvidiafb_probe(), the memory allocated for modelist in nvidia_set_fbinfo() is not freed in the subsequent error paths. Fix that by calling fb_destroy_modelist().
--- drivers/video/fbdev/nvidia/nvidia.c | 1 + 1 file changed, 1 insertion(+)
drivers/video/fbdev/nvidia/nvidia.c +1 -0
@@ -1418,6 +1418,7 @@ static int nvidiafb_probe(struct pci_dev err_out_iounmap_fb:iounmap (info->screen_base); +fb_destroy_modelist (&info->modelist); err_out_free_base1:fb_destroy_modedb (info->monspecs.modedb);nvidia_delete_i2c_busses (par);
Greg Kroah-Hartman
maintainerPATCH 739/1067 fbdev: tridentfb: fix potential memory leak in trident_pci_probe()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 7a35ec619d9af8ee128320975c1252b8ad65f1e8 upstream.
In trident_pci_probe(), the memory allocated for modelist using fb_videomode_to_modelist() is not freed in subsequent error paths. Fix that by calling fb_destroy_modelist().
--- drivers/video/fbdev/tridentfb.c | 1 + 1 file changed, 1 insertion(+)
drivers/video/fbdev/tridentfb.c +1 -0
@@ -1705,6 +1705,7 @@ static int trident_pci_probe(struct pci_return 0 ; out_unmap2: +fb_destroy_modelist (&info->modelist);if (default_par->ddc_registered)i2c_del_adapter (&default_par->ddc_adapter);kfree (info->pixmap.addr);
Greg Kroah-Hartman
maintainerPATCH 740/1067 ASoC: SOF: ipc3-control: Validate size in snd_sof_update_control
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Peter Ujfalusi <[email protected]>
commit 390aa4c9339bb0ec0bc8d554e830faf93ca9d49e upstream.
In snd_sof_update_control(), firmware-provided cdata->num_elems is checked against local_cdata->data->size but never against the actual allocation size. If local_cdata->data->size was previously set to an inconsistent value, the memcpy could write past the allocated buffer.
Add a bounds check to ensure num_elems fits within the available space in the ipc_control_data allocation before copying.
--- sound/soc/sof/ipc3-control.c | 9 +++++++++ 1 file changed, 9 insertions(+)
sound/soc/sof/ipc3-control.c +9 -0
@@ -522,6 +522,15 @@ static void snd_sof_update_control(strucreturn ; } +/* Verify the size fits within the allocation */ +if (cdata->num_elems > scontrol->max_size -sizeof (*local_cdata) - +sizeof (*local_cdata->data)) { +dev_err (scomp->dev, +"cdata binary size %u exceeds buffer\n" , + cdata->num_elems); +return ; + } +/* copy the new binary data */ memcpy (local_cdata->data, cdata->data, cdata->num_elems); }else if (cdata->num_elems != scontrol->num_channels) {
Greg Kroah-Hartman
maintainerPATCH 741/1067 ASoC: qcom: q6apm: fix NULL pointer dereference in graph_callback
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Srinivas Kandagatla <[email protected]>
commit 2e9261761b35f0b67b7487688cd1365f535be0b3 upstream.
When q6apm_free_fragments() is called it frees rx_data.buf/tx_data.buf and sets them to NULL under graph->lock. A late DSP buffer-done response can race with this: graph_callback() passes the !graph->ar_graph guard (not yet NULL), acquires the lock, but then dereferences a now-NULL buf pointer to read buf[token].phys, crashing at virtual address 0x10.
Add a NULL check for buf inside the mutex-protected section in both the write-done (DATA_CMD_RSP_WR_SH_MEM_EP_DATA_BUFFER_DONE_V2) and read-done (DATA_CMD_RSP_RD_SH_MEM_EP_DATA_BUFFER_V2) handlers and bail out cleanly if buffers have already been freed.
This problem is only shown up recently while apr bus was updated to process the commands per service rather from single global queue.
--- sound/soc/qcom/qdsp6/q6apm.c | 8 ++++++++ 1 file changed, 8 insertions(+)
sound/soc/qcom/qdsp6/q6apm.c +8 -0
@@ -524,6 +524,10 @@ static int graph_callback(struct gpr_res token = hdr->token &APM_WRITE_TOKEN_MASK ; done = data->payload; +if (!graph->rx_data.buf) { +mutex_unlock (&graph->lock); +break ; + } phys = graph->rx_data.buf[token].phys;mutex_unlock (&graph->lock);
@@ -557,6 +561,10 @@ static int graph_callback(struct gpr_res client_event =APM_CLIENT_EVENT_DATA_READ_DONE ;mutex_lock (&graph->lock); rd_done = data->payload; +if (!graph->tx_data.buf) { +mutex_unlock (&graph->lock); +break ; + } phys = graph->tx_data.buf[hdr->token].phys;mutex_unlock (&graph->lock);
Greg Kroah-Hartman
maintainerPATCH 742/1067 netfilter: nf_conntrack_irc: fix parse_dcc() off-by-one OOB read
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
commit ef6400ca25a13fd6dedbe8ef4a1d0979bbbfe88a upstream.
parse_dcc() treats data_end as an inclusive end pointer, but its only caller passes data_limit = ib_ptr + datalen, which points one past the last valid byte.
The newline search loop iterates while tmp <= data_end, so when no newline is present, *tmp is read at tmp == data_end, one byte beyond the region filled by skb_header_pointer().
irc_buffer is kmalloc'd as MAX_SEARCH_SIZE + 1 bytes and datalen is capped at MAX_SEARCH_SIZE, so the stray read does not fault. The byte is uninitialized or stale; if it contains an ASCII digit, simple_strtoul will consume it and produce a wrong DCC IP or port in the conntrack expectation. The extra allocation byte is also a fragile guard: if the cap or allocation size changes, this becomes a real out-of-bounds read.
Change the loop and its post-loop check to use strict less-than, consistent with the caller's exclusive-end convention. Update the function comment accordingly.
--- net/netfilter/nf_conntrack_irc.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/netfilter/nf_conntrack_irc.c +3 -3
@@ -64,7 +64,7 @@ static const char *const dccprotos[] = {/* tries to get the ip_addr and port out of a dcc command * return value: -1 on failure, 0 on success * data pointer to first byte of DCC command data -* data_end pointer to last byte of dcc command data +* data_end one past end of data * ip returns parsed ip of dcc command * port returns parsed port of dcc command * ad_beg_p returns pointer to first byte of addr data
@@ -82,10 +82,10 @@ static int parse_dcc(char *data, const c/* Make sure we have a newline character within the packet boundaries * because simple_strtoul parses until the first invalid character. */ -for (tmp = data; tmp <= data_end; tmp++) +for (tmp = data; tmp < data_end; tmp++)if (*tmp =='\n' )break ; -if (tmp > data_end || *tmp !='\n' ) +if (tmp >= data_end || *tmp !='\n' )return -1 ; *ad_beg_p = data;
Greg Kroah-Hartman
maintainerPATCH 743/1067 netfilter: nfnl_cthelper: apply per-class values when updating policies
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: David Carlier <[email protected]>
commit d738feccb98cb224ebabecb703e98f5008276bff upstream.
When a userspace conntrack helper with multiple expectation classes is updated via nfnetlink, every class ends up with the first class's max_expected and timeout values.
nfnl_cthelper_update_policy_all() validates each new policy into the corresponding slot of the temporary new_policy array, but the second loop that commits the values into the live helper dereferences new_policy as a pointer instead of indexing it, so every iteration reads new_policy[0] regardless of i. An update that changes per-class values is silently collapsed onto class 0's values with no error returned to userspace.
Index the temporary array by i in the commit loop so each class gets its own validated values.
--- net/netfilter/nfnetlink_cthelper.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/netfilter/nfnetlink_cthelper.c +2 -2
@@ -348,8 +348,8 @@ static int nfnl_cthelper_update_policy_afor (i =0 ; i < helper->expect_class_max +1 ; i++) { policy = (struct nf_conntrack_expect_policy *) &helper->expect_policy[i]; - policy->max_expected = new_policy->max_expected; - policy->timeout = new_policy->timeout; + policy->max_expected = new_policy[i].max_expected; + policy->timeout = new_policy[i].timeout; } err:
Greg Kroah-Hartman
maintainerPATCH 744/1067 netfilter: xt_cluster: reject template conntracks in hash match
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
commit 5feba91006ec92da57acc1cc2e34df623b98541e upstream.
xt_cluster_mt() treats any non-NULL nf_ct_get() result as a fully initialized conntrack and passes it to xt_cluster_hash().
This causes a state confusion bug when the raw table CT target attaches a template conntrack to skb->_nfct before normal conntrack processing. Templates carry IPS_TEMPLATE status but do not have a valid tuple for hashing yet, so xt_cluster_hash() can hit its WARN_ON() path on the zeroed l3num field.
Reject template conntracks before hashing them. This matches existing netfilter handling for template objects and avoids hashing incomplete conntrack state.
--- net/netfilter/xt_cluster.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/xt_cluster.c +1 -1
@@ -107,7 +107,7 @@ xt_cluster_mt(const struct sk_buff *skb, } ct =nf_ct_get (skb, &ctinfo); -if (ct ==NULL ) +if (!ct ||nf_ct_is_template (ct))return false;if (ct->master)
Greg Kroah-Hartman
maintainerPATCH 745/1067 netfilter: nf_queue: pin bridge device while NFQUEUE holds fake dst
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoze Xie <[email protected]>
commit c9c9b37f8c5505224e8d206184df3bb668ee00cf upstream.
The br_netfilter fake rtable is embedded in struct net_bridge and is attached to bridged packets with skb_dst_set_noref(). If such a packet is queued to NFQUEUE, __nf_queue() upgrades that fake dst with skb_dst_force().
At that point the queued skb can hold a real dst reference after bridge teardown has started. The problem is not that every bridged packet needs its own dst reference. The problem is that NFQUEUE can keep the bridge private fake dst alive after unregister begins.
Fix this by keeping the bridge fake dst model unchanged and pinning the bridge master device only while the packet sits in NFQUEUE. Record the bridge device in nf_queue_entry when the queued skb carries a bridge fake dst, take a device reference for the queue lifetime, and drop it when the queue entry is freed.
Also make sure queued entries are reaped when that bridge device goes down, and drop the redundant nf_bridge_info_exists() test from the fake dst detection.
This keeps netdev_priv(br->dev) alive until verdict completion, so the embedded fake rtable and its metrics backing storage cannot be freed out from under dst_release(). It also avoids the constant refcount bump and avoids using ipv4-specific dst helpers for IPv6 bridge traffic.
--- include/net/netfilter/nf_queue.h | 1 + net/netfilter/nf_queue.c | 14 ++++++++++++++ net/netfilter/nfnetlink_queue.c | 3 +++ 3 files changed, 18 insertions(+)
include/net/netfilter/nf_queue.h +1 -0
@@ -16,6 +16,7 @@ struct nf_queue_entry {unsigned int id;unsigned int hook_index;/* index in hook_entries->hook[] */ #if IS_ENABLED (CONFIG_BRIDGE_NETFILTER ) +struct net_device *bridge_dev;struct net_device *physin;struct net_device *physout;#endif
net/netfilter/nf_queue.c +14 -0
@@ -67,6 +67,7 @@ static void nf_queue_entry_release_refs(nf_queue_sock_put (state->sk);#if IS_ENABLED (CONFIG_BRIDGE_NETFILTER ) +dev_put (entry->bridge_dev);dev_put (entry->physin);dev_put (entry->physout);#endif
@@ -83,6 +84,8 @@ static void __nf_queue_entry_init_physde {#if IS_ENABLED (CONFIG_BRIDGE_NETFILTER )const struct sk_buff *skb = entry->skb; +struct dst_entry *dst =skb_dst (skb); +struct net_device *dev =NULL ;if (nf_bridge_info_exists (skb)) { entry->physin =nf_bridge_get_physindev (skb, entry->state.net);
@@ -91,6 +94,16 @@ static void __nf_queue_entry_init_physde entry->physin =NULL ; entry->physout = NULL; } + +if (entry->state.pf ==NFPROTO_BRIDGE && + dst && (dst->flags &DST_FAKE_RTABLE )) + dev =dst_dev_rcu (dst); + +/* Must hold a reference on the bridge device: dst_hold() protects +* the dst itself, but the fake rtable is embedded in bridge-private +* storage that netdevice teardown can free independently. +*/ + entry->bridge_dev = dev;#endif }
@@ -107,6 +120,7 @@ bool nf_queue_entry_get_refs(struct nf_qdev_hold (state->out);#if IS_ENABLED (CONFIG_BRIDGE_NETFILTER ) +dev_hold (entry->bridge_dev);dev_hold (entry->physin);dev_hold (entry->physout);#endif
net/netfilter/nfnetlink_queue.c +3 -0
@@ -950,6 +950,9 @@ dev_cmp(struct nf_queue_entry *entry, unif (physinif == ifindex || physoutif == ifindex)return 1 ; + +if (entry->bridge_dev && entry->bridge_dev->ifindex == ifindex) +return 1 ;#endif if (entry->skb_dev && entry->skb_dev->ifindex == ifindex)return 1 ;
Greg Kroah-Hartman
maintainerPATCH 746/1067 netfilter: nf_nat_sip: reload possible stale data pointer
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Westphal <[email protected]>
commit 77e43bcb7ec177e293a5c3f1b91a2c5aebfb6c68 upstream.
quoting sashiko:
------------------------------------------------------------------------
[..] noticed a potential memory bug and header corruption involving the SIP NAT helper.
In net/netfilter/nf_nat_sip.c:nf_nat_sip():
if (skb_ensure_writable(skb, skb->len)) {
nf_ct_helper_log(skb, ct, "cannot mangle packet");
return NF_DROP;
}
uh = (void *)skb->data + protoff;
uh->dest = ct_sip_info->forced_dport;
if (!nf_nat_mangle_udp_packet(skb, ct, ctinfo, protoff,
0, 0, NULL, 0)) { If a cloned or fragmented SKB is reallocated by skb_ensure_writable(), the old data buffer is freed. However, nf_nat_sip() fails to update *dptr to point to the new buffer.
It also appears to use nf_nat_mangle_udp_packet() on what could be a TCP packet, which would overwrite the sequence number with a checksum update.
------------------------------------------------------------------------
nf_conntrack_sip linerizes skbs, hence no fragmented skb can be seen. But clones are possible, so rebuild dptr.
Disable nf_nat_mangle_udp_packet() branch for TCP streams. It doesn't look like this can ever happen, else we should have received bug reports about this, so just check the conntrack is UDP and drop otherwise.
The calling conntrack_sip set ->forced_dport for SIP_HDR_VIA_UDP messages, so I don't think this is ever expected to be true for a TCP stream.
--- net/netfilter/nf_nat_sip.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
net/netfilter/nf_nat_sip.c +11 -0
@@ -283,13 +283,24 @@ next:/* Mangle destination port for Cisco phones, then fix up checksums */ if (dir ==IP_CT_DIR_REPLY && ct_sip_info->forced_dport) { +int doff = *dptr - (const char *)skb->data;struct udphdr *uh; +if (doff <=0 ) { +DEBUG_NET_WARN_ON_ONCE (1 ); +return NF_DROP ; + } + +/* ct_sip_info->forced_dport only expected with UDP */ +if (nf_ct_protonum (ct) !=IPPROTO_UDP ) +return NF_DROP ; +if (skb_ensure_writable (skb, skb->len)) {nf_ct_helper_log (skb, ct,"cannot mangle packet" );return NF_DROP ; } + *dptr = skb->data + doff; uh = (void *)skb->data + protoff; uh->dest = ct_sip_info->forced_dport;
Greg Kroah-Hartman
maintainerPATCH 747/1067 netfilter: nf_conntrack_reasm: guard mac_header adjustment after IPv6 defrag
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei <[email protected]>
commit 3b08fed5b7e0d5e3a25d73ef3ba09cd33ade16c9 upstream.
nf_ct_frag6_reasm() slides the packet head forward to drop the IPv6 fragment header and then unconditionally advances skb->mac_header:
skb->mac_header += sizeof(struct frag_hdr);
On the NF_INET_LOCAL_OUT defrag path the skb has no link-layer header yet, so skb->mac_header is still the "not set" sentinel (u16)~0U. Adding sizeof(struct frag_hdr) wraps it to a small value (0xffff + 8 == 7), after which skb_mac_header_was_set() wrongly reports a MAC header is present and skb_mac_header() points into the headroom.
The reassembler has done this unconditional add since it was introduced; it was harmless while mac_header was a bare pointer, but wrong once mac_header became a u16 offset whose unset state is the ~0U sentinel tested by skb_mac_header_was_set(). The sibling net/ipv6/reassembly.c does the same relocation and does guard the adjustment; mirror the guard here.
--- net/ipv6/netfilter/nf_conntrack_reasm.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/ipv6/netfilter/nf_conntrack_reasm.c +2 -1
@@ -345,7 +345,8 @@ static int nf_ct_frag6_reasm(struct fragskb_network_header (skb)[fq->nhoffset] =skb_transport_header (skb)[0 ];memmove (skb->head +sizeof (struct frag_hdr ), skb->head, (skb->data - skb->head) -sizeof (struct frag_hdr )); - skb->mac_header +=sizeof (struct frag_hdr ); +if (skb_mac_header_was_set (skb)) + skb->mac_header +=sizeof (struct frag_hdr ); skb->network_header +=sizeof (struct frag_hdr );skb_reset_transport_header (skb);
Greg Kroah-Hartman
maintainerPATCH 748/1067 netfilter: nf_conncount: fix zone comparison in tuple dedup
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
commit f62c41b4910e65da396ec9a8c40c1fe7fe82e449 upstream.
The "already exists" dedup logic in __nf_conncount_add() decides whether a connection has already been counted and can be skipped instead of incrementing the connlimit count. It compares the conntrack zone of a list entry with the zone of the connection being added using nf_ct_zone_id() and nf_ct_zone_equal(), passing conn->zone.dir or zone->dir as the direction argument.
Those helpers take enum ip_conntrack_dir values: IP_CT_DIR_ORIGINAL is 0 and IP_CT_DIR_REPLY is 1. However, zone->dir is a u8 bitmask:NF_CT_ZONE_DIR_ORIG is 1, NF_CT_ZONE_DIR_REPL is 2 and NF_CT_DEFAULT_ZONE_DIR is 3. Passing that bitmask as the enum direction shifts the meaning of every non-zero value. An ORIG-only zone passes 1 and is tested as REPLY, while REPL-only and default zones pass 2 or 3 and test bits beyond the valid direction range. In those cases nf_ct_zone_id() can fall back to NF_CT_DEFAULT_ZONE_ID instead of using the real zone id, so different zones can be treated as equal and dedup collapses to tuple equality alone.
nf_conncount stores and compares the original-direction tuple for a connection. If an skb already has an attached conntrack entry, get_ct_or_tuple_from_skb() explicitly copies ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple, regardless of the packet's ctinfo. Therefore the zone comparison in the tuple dedup path must use IP_CT_DIR_ORIGINAL as well; the zone direction bitmask describes where a zone id applies, not which direction this conncount tuple represents.
Fix the two dedup comparisons by passing IP_CT_DIR_ORIGINAL directly. Do not special-case NF_CT_DEFAULT_ZONE_DIR and do not compare raw zone
ids: using the existing helpers with IP_CT_DIR_ORIGINAL preserves the direction-aware NF_CT_DEFAULT_ZONE_ID fallback. A default bidirectional zone contains the ORIG bit, so it naturally returns the real zone id; reply-only zones continue to fall back for original-direction tuple comparisons.
--- net/netfilter/nf_conncount.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
net/netfilter/nf_conncount.c +3 -3
@@ -207,8 +207,8 @@ check_connections:/* Not found, but might be about to be confirmed */ if (PTR_ERR (found) == -EAGAIN ) {if (nf_ct_tuple_equal (&conn->tuple, &tuple) && -nf_ct_zone_id (&conn->zone, conn->zone.dir) == -nf_ct_zone_id (zone, zone->dir)) +nf_ct_zone_id (&conn->zone,IP_CT_DIR_ORIGINAL ) == +nf_ct_zone_id (zone,IP_CT_DIR_ORIGINAL )) goto out_put;/* already exists */ }else { collect++;
@@ -219,7 +219,7 @@ check_connections: found_ct =nf_ct_tuplehash_to_ctrack (found);if (nf_ct_tuple_equal (&conn->tuple, &tuple) && -nf_ct_zone_equal (found_ct, zone, zone->dir)) { +nf_ct_zone_equal (found_ct, zone,IP_CT_DIR_ORIGINAL )) {/* * We should not see tuples twice unless someone hooks * this into a table without "-p tcp --syn".
Greg Kroah-Hartman
maintainerPATCH 749/1067 netfilter: ecache: fix inverted time_after() check
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yizhou Zhao <[email protected]>
commit b06163ce52ec0561f202fbfb9b08090cb61f512e upstream.
ecache_work_evict_list() redelivers DESTROY events for conntracks that were moved to the per-netns dying_list after event delivery failed. It sets a 10ms deadline:
stop = jiffies + ECACHE_MAX_JIFFIES
but then tests:
time_after(stop, jiffies)
This condition is true while the deadline is still in the future, so the worker returns STATE_RESTART after the first successful redelivery in the usual case. ecache_work() maps STATE_RESTART to delay 0, which turns the redelivery path into one dying conntrack per workqueue dispatch and makes the sent > 16 batching/cond_resched() path effectively unreachable.
A conntrack netlink listener whose receive queue is congested can make DESTROY event delivery fail with -ENOBUFS. With sustained conntrack churn, entries then accumulate on the dying_list and are only drained at the degraded one-entry-per-dispatch rate once delivery succeeds again, wasting CPU on back-to-back workqueue reschedules and prolonging conntrack memory/resource pressure.
In a KASAN QEMU test with CONFIG_NF_CONNTRACK_EVENTS=y and nf_conntrack.enable_hooks=1, a congested DESTROY listener caused 8192 nf_ct_delete() calls to return false and move entries to the dying_list. After closing the listener, the unfixed kernel needed 7670 ecache_work() entries to destroy 7669 conntracks. With this change, the same 8192 entries were destroyed by 2 ecache_work() entries.
Swap the comparison so the worker restarts only after the deadline has expired.
--- net/netfilter/nf_conntrack_ecache.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/netfilter/nf_conntrack_ecache.c +1 -1
@@ -77,7 +77,7 @@ next:hlist_nulls_del_rcu (&ct->tuplehash[IP_CT_DIR_ORIGINAL ].hnnode);hlist_nulls_add_head (&ct->tuplehash[IP_CT_DIR_REPLY ].hnnode, &evicted_list); -if (time_after (stop, jiffies)) { +if (time_after (jiffies, stop)) { ret =STATE_RESTART ;break ; }
Greg Kroah-Hartman
maintainerPATCH 750/1067 netfilter: xt_nat: reject unsupported target families
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wyatt Feng <[email protected]>
commit 5d1a2240935ea47e2673d0ea17fdb058e4dc91dd upstream.
xt_nat SNAT and DNAT target handlers assume IP-family conntrack state is present and can dereference a NULL pointer when instantiated from an unsupported family through nft_compat. A bridge-family compat rule can therefore trigger a NULL-dereference in nf_nat_setup_info().
Reject non-IP families in xt_nat_checkentry() so unsupported targets cannot be installed. Keep NFPROTO_INET allowed for valid inet NAT compat users and leave the runtime fast path unchanged.
[ The crash was fixed via
9dbba7e694ec ("netfilter: nft_compat: ebtables emulation must reject non-bridge targets"), so this patch is no longer critical.
Nevertheless, NAT is only relevant for ipv4/ipv6, so this extra
family check is a good idea in any case. ]
--- net/netfilter/xt_nat.c | 9 +++++++++ 1 file changed, 9 insertions(+)
net/netfilter/xt_nat.c +9 -0
@@ -26,6 +26,15 @@ static int xt_nat_checkentry_v0(const ststatic int xt_nat_checkentry (const struct xt_tgchk_param *par) { +switch (par->family) { +case NFPROTO_IPV4 : +case NFPROTO_IPV6 : +case NFPROTO_INET : +break ; +default : +return -EINVAL ; + } +return nf_ct_netns_get (par->net, par->family); }
Greg Kroah-Hartman
maintainerPATCH 751/1067 netfilter: bridge: fix stale prevhdr pointer in br_ip6_fragment()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xiang Mei (Microsoft) <[email protected]>
commit 86f3ce81dd2b4b0aa2c3016c989a943e4b1b643d upstream.
br_ip6_fragment() gets prevhdr, a pointer into the skb head, from ip6_find_1stfragopt(), then calls skb_checksum_help(). For a cloned skb skb_checksum_help() reallocates the head via pskb_expand_head(), leaving prevhdr dangling. It is later dereferenced in ip6_frag_next(), causing a use-after-free write.
Save prevhdr's offset before skb_checksum_help() and recompute it after, like commit ef0efcd3bd3f ("ipv6: Fix dangling pointer when ipv6 fragment").
BUG: KASAN: slab-use-after-free in ip6_frag_next (net/ipv6/ip6_output.c:857) Write of size 1 at addr ffff888013ff5016 by task exploit/141 Call Trace: ... kasan_report (mm/kasan/report.c:595) ip6_frag_next (net/ipv6/ip6_output.c:857) br_ip6_fragment (net/ipv6/netfilter.c:212) nf_ct_bridge_post (net/bridge/netfilter/nf_conntrack_bridge.c:407) nf_hook_slow (net/netfilter/core.c:619) br_forward_finish (net/bridge/br_forward.c:66) __br_forward (net/bridge/br_forward.c:115) maybe_deliver (net/bridge/br_forward.c:191) br_flood (net/bridge/br_forward.c:245) br_handle_frame_finish (net/bridge/br_input.c:229) br_handle_frame (net/bridge/br_input.c:442) ... packet_sendmsg (net/packet/af_packet.c:3114) ... do_syscall_64 (arch/x86/entry/syscall_64.c:94) entry_SYSCALL_64_after_hwframe (arch/x86/entry/entry_64.S:121) Kernel panic - not syncing: Fatal exception in interrupt
--- net/ipv6/netfilter.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
net/ipv6/netfilter.c +3 -1
@@ -130,7 +130,7 @@ int br_ip6_fragment(struct net *net, strktime_t tstamp = skb->tstamp;struct ip6_frag_state state;u8 *prevhdr, nexthdr =0 ; -unsigned int mtu, hlen; +unsigned int mtu, hlen, nexthdr_offset;int hroom, err =0 ;__be32 frag_id;
@@ -139,6 +139,7 @@ int br_ip6_fragment(struct net *net, str goto blackhole; hlen = err; nexthdr = *prevhdr; + nexthdr_offset = prevhdr -skb_network_header (skb); mtu = skb->dev->mtu; if (frag_max_size > mtu ||
@@ -157,6 +158,7 @@ int br_ip6_fragment(struct net *net, str (err = skb_checksum_help(skb))) goto blackhole; + prevhdr =skb_network_header (skb) + nexthdr_offset; hroom =LL_RESERVED_SPACE (skb->dev);if (skb_has_frag_list (skb)) {unsigned int first_len =skb_pagelen (skb);
Greg Kroah-Hartman
maintainerPATCH 752/1067 gpu: host1x: Fix device reference leak in host1x_device_parse_dt() error path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit e75717f9aec04355777be41070890c6a815c76df upstream.
After device_initialize(), the embedded struct device in struct host1x_device should be released through the device core with put_device().
In host1x_device_add(), if host1x_device_parse_dt() fails, the current error path frees the object directly with kfree(device). That bypasses the normal device lifetime handling and leaks the reference held on the embedded struct device.
The issue was identified by a static analysis tool I developed and confirmed by manual review.
Fix this by using put_device() in the host1x_device_parse_dt() failure path.
--- drivers/gpu/host1x/bus.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/gpu/host1x/bus.c +1 -1
@@ -474,7 +474,7 @@ static int host1x_device_add(struct host err =host1x_device_parse_dt (device, driver);if (err <0 ) { -kfree (device); +put_device (&device->dev);return err; }
Greg Kroah-Hartman
maintainerPATCH 753/1067 soc: ti: k3-ringacc: Fix access mode for k3_ringacc_ring_pop_tail_io/proxy
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Siddharth Vadapalli <[email protected]>
commit b920352cfd2b0fcd1249ff006618c939b64fc8f7 upstream.
k3_ringacc_ring_pop_tail_io() and k3_ringacc_ring_pop_tail_proxy() incorrectly use K3_RINGACC_ACCESS_MODE_POP_HEAD instead of K3_RINGACC_ACCESS_MODE_POP_TAIL. This will result in ring elements being popped in the reverse order of that which the caller expects. Fix this.
--- drivers/soc/ti/k3-ringacc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/soc/ti/k3-ringacc.c +2 -2
@@ -997,7 +997,7 @@ static int k3_ringacc_ring_pop_head_proxstatic int k3_ringacc_ring_pop_tail_proxy (struct k3_ring *ring,void *elem) {return k3_ringacc_ring_access_proxy (ring, elem, -K3_RINGACC_ACCESS_MODE_POP_HEAD ); +K3_RINGACC_ACCESS_MODE_POP_TAIL ); } static int k3_ringacc_ring_access_io(struct k3_ring *ring, void *elem,
@@ -1068,7 +1068,7 @@ static int k3_ringacc_ring_pop_io(structstatic int k3_ringacc_ring_pop_tail_io (struct k3_ring *ring,void *elem) {return k3_ringacc_ring_access_io (ring, elem, -K3_RINGACC_ACCESS_MODE_POP_HEAD ); +K3_RINGACC_ACCESS_MODE_POP_TAIL ); }/*
Greg Kroah-Hartman
maintainerPATCH 754/1067 soc: fsl: qe: panic on ioremap() failure in qe_reset()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wang Jun <[email protected]>
commit a0fe29d20e7822182e12324905af5115c1b3aed3 upstream.
When ioremap() fails in qe_reset(), the global pointer qe_immr remains NULL, leading to a subsequent NULL pointer dereference when the pointer is accessed. Since this happens early in the boot process, a failure to map a few bytes of I/O memory indicates a fatal error from which the system cannot recover.
Follow the same pattern as qe_sdma_init() and panic immediately when ioremap() fails. This avoids a silent NULL pointer dereference later and makes the error explicit.
--- drivers/soc/fsl/qe/qe.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/soc/fsl/qe/qe.c +3 -0
@@ -88,6 +88,9 @@ void qe_reset(void)if (qe_immr ==NULL ) qe_immr =ioremap (get_qe_base (),QE_IMMAP_SIZE ); +if (!qe_immr) +panic ("QE:ioremap failed!" ); +qe_snums_init (); qe_issue_cmd(QE_RESET, QE_CR_SUBBLOCK_INVALID,
Greg Kroah-Hartman
maintainerPATCH 755/1067 selinux: check connect-related permissions on TCP Fast Open
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephen Smalley <[email protected]>
commit 44c74d27d1b9aaa99fa8a83640c1223575262b80 upstream.
Similar to Landlock, SELinux was not updated when TCP Fast Open support was introduced to ensure connect-related permissions are checked when using TCP Fast Open. Update its socket_sendmsg() hook to call selinux_socket_connect() when MSG_FASTOPEN is passed.
--- security/selinux/hooks.c | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-)
security/selinux/hooks.c +18 -1
@@ -4957,7 +4957,24 @@ static int selinux_socket_accept(structstatic int selinux_socket_sendmsg (struct socket *sock,struct msghdr *msg,int size) { -return sock_has_perm (sock->sk,SOCKET__WRITE ); +int rc; +struct sockaddr *const addr = msg->msg_name; +const int addrlen = msg->msg_namelen; + + rc =sock_has_perm (sock->sk,SOCKET__WRITE ); +if (rc) +return rc; + +if (addr && (msg->msg_flags &MSG_FASTOPEN ) && + (sk_is_tcp (sock->sk) || + (sk_is_inet (sock->sk) && sock->sk->sk_type ==SOCK_STREAM && + sock->sk->sk_protocol ==IPPROTO_MPTCP ))) { + rc =selinux_socket_connect (sock, addr, addrlen); +if (rc) +return rc; + } + +return 0 ; } static int selinux_socket_recvmsg(struct socket *sock, struct msghdr *msg,
Greg Kroah-Hartman
maintainerPATCH 756/1067 leds: uleds: Fix potential buffer overread
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Armin Wolf <[email protected]>
commit c19fe864f667afc49d1391d764e20b66555bcf7a upstream.
The name string supplied by userspace is not guaranteed to be null-terminated, so using strchr() on it might result in a buffer overread. The same thing will happen when said string is used by the LED class device.
Fix this by using strnchr() instead and explicitly check that the name string is properly null-terminated.
--- drivers/leds/uleds.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/leds/uleds.c +2 -1
@@ -102,7 +102,8 @@ static ssize_t uleds_write(struct file * name = udev->user_dev.name;if (!name[0 ] || !strcmp (name,"." ) || !strcmp (name,".." ) || -strchr (name,'/' )) { +strnchr (name,sizeof (udev->user_dev.name),'/' ) || + !strnchr (name,sizeof (udev->user_dev.name),'\0' )) { ret = -EINVAL ; goto out; }
Greg Kroah-Hartman
maintainerPATCH 757/1067 mfd: sm501: Fix reference leak on failed device registration
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guangshuo Li <[email protected]>
commit 8c2f0b42fc252e1bf1c7746447091a468e784ca1 upstream.
When platform_device_register() fails in sm501_register_device(), the embedded struct device in pdev has already been initialized by device_initialize(), but the failure path only reports the error and returns without dropping the device reference for the current platform device:
sm501_register_device()
-> platform_device_register(pdev)
-> device_initialize(&pdev->dev)
-> setup_pdev_dma_masks(pdev)
-> platform_device_add(pdev)This leads to a reference leak when platform_device_register() fails. Fix this by calling platform_device_put() before returning the error.
The issue was identified by a static analysis tool I developed and confirmed by manual review.
--- drivers/mfd/sm501.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/mfd/sm501.c +3 -1
@@ -747,9 +747,11 @@ static int sm501_register_device(structif (ret >=0 ) {dev_dbg (sm->dev,"registered %s\n" , pdev->name);list_add_tail (&smdev->list, &sm->devices); - }else + }else {dev_err (sm->dev,"error registering %s (%d)\n" , pdev->name, ret); +platform_device_put (pdev); + }return ret; }
Greg Kroah-Hartman
maintainerPATCH 758/1067 tools/power/x86/intel-speed-select: Harden daemon pidfile open
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet MEMIS <[email protected]>
commit 607af438e6430893a822964c841a1994b33acccc upstream.
Avoid symlink-based pidfile clobbering by opening the pidfile with O_NOFOLLOW and validating it with fstat() before locking/writing.
The daemon currently uses a fixed pidfile path under /tmp. A local unprivileged user can pre-create a symlink at that path and cause a root-run daemon instance to write into an attacker-chosen file.
--- tools/power/x86/intel-speed-select/isst-daemon.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
tools/power/x86/intel-speed-select/isst-daemon.c +8 -1
@@ -133,6 +133,7 @@ static void daemonize(char *rundir, char {int pid, sid, i;char str[10 ]; +struct stat st;struct sigaction sig_actions;sigset_t sig_set;int ret;
@@ -186,11 +187,17 @@ static void daemonize(char *rundir, charif (ret ==-1 )exit (EXIT_FAILURE ); - pid_file_handle =open (pidfile,O_RDWR |O_CREAT ,0600 ); + pid_file_handle =open (pidfile,O_RDWR |O_CREAT |O_NOFOLLOW ,0600 );if (pid_file_handle ==-1 ) {/* Couldn't open lock file */ exit (1 ); } + +if (fstat (pid_file_handle, &st) ==-1 ) +exit (1 ); + +if (!S_ISREG (st.st_mode)) +exit (1 );/* Try to lock file */ #ifdef LOCKF_SUPPORT if (lockf (pid_file_handle,F_TLOCK ,0 ) ==-1 ) {
Greg Kroah-Hartman
maintainerPATCH 759/1067 x86/boot: Validate console=uart8250 baud rate to fix early boot hang
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit ffa0aa5b625fe0bed7463ac613f8b06676ff4542 upstream.
When the baud rate is empty, 0, invalid, or overflows to 0 when stored as an int, the system will hang during early boot because of a division by zero in early_serial_init().
Fall back to DEFAULT_BAUD when the resulting baud rate is 0 to prevent an early system hang.
--- arch/x86/boot/early_serial_console.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
arch/x86/boot/early_serial_console.c +7 -4
@@ -117,7 +117,7 @@ static unsigned int probe_baud(int port)static void parse_console_uart8250 (void ) {char optstr[64 ], *options; -int baud =DEFAULT_BAUD ; +int baud;int port =0 ;/*
@@ -136,10 +136,13 @@ static void parse_console_uart8250(void)else return ; -if (options && (options[0 ] ==',' )) - baud =simple_strtoull (options +1 , &options,0 ); -else +if (options && (options[0 ] ==',' )) { + baud =simple_strtoull (options +1 ,NULL ,0 ); +if (!baud) + baud =DEFAULT_BAUD ; + }else { baud =probe_baud (port); + }if (port)early_serial_init (port, baud);
Greg Kroah-Hartman
maintainerPATCH 760/1067 x86/boot: Reject too long acpi_rsdp= values
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thorsten Blum <[email protected]>
commit d130041a7b96f79cd4c7079a6c2431a6db4c9619 upstream.
cmdline_find_option() returns the full length of the parsed acpi_rsdp= value. get_cmdline_acpi_rsdp() then silently truncates values which do not fit in the val[] buffer.
Prevent boot_kstrtoul() from parsing a truncated value and then the kernel from silently using the wrong RSDP address, see discussion in Link:.
Issue a warning so that the user is aware that s/he supplied a malformed value and can get feedback instead of silent crashes.
[ bp: Make commit message more precise. ]
--- arch/x86/boot/compressed/acpi.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-)
arch/x86/boot/compressed/acpi.c +6 -1
@@ -182,10 +182,15 @@ static unsigned long get_cmdline_acpi_rschar val[MAX_ADDR_LEN ] = { };int ret; - ret =cmdline_find_option ("acpi_rsdp" , val,MAX_ADDR_LEN ); + ret =cmdline_find_option ("acpi_rsdp" , val,sizeof (val));if (ret <0 )return 0 ; +if (ret >=sizeof (val)) { +warn ("acpi_rsdp= value too long; ignoring" ); +return 0 ; + } +if (boot_kstrtoul (val,16 , &addr))return 0 ;#endif
Greg Kroah-Hartman
maintainerPATCH 761/1067 perf/x86/amd/lbr: Fix kernel address leakage
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sandipan Das <[email protected]>
commit 2a892294b83f541115c94b0bb637f39bef187657 upstream.
A user-only branch stack can contain branches that originate from the kernel. As a result, kernel addresses are exposed to user space even when PERF_SAMPLE_BRANCH_USER is requested. On AMD processors supporting X86_FEATURE_AMD_LBR_V2, perf can still report SYSRET/ERET entries for which the branch-from addresses are in the kernel.
E.g.
$ perf record -e cycles -o - -j any,save_type,u -- \
perf bench syscall basic --loop 1000 | \
perf script -i - -F brstack|tr ' ' '\n'| \
grep -E '0x[89a-f][0-9a-f]{15}' ...
0xffffffff81001268/0x717a90a38f1a/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH 0xffffffff81001268/0x717a90a39157/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH 0xffffffff81001268/0x717a90a2c628/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH 0xffffffff81001268/0x717a90a41b60/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH 0xffffffff81001268/0x717a90a260db/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH 0xffffffff81001268/0x717a90a260db/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH 0xffffffff81001268/0x717a8bef1c30/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH 0xffffffff81001268/0x717a8e4d3c90/M/-/-/0/ERET/NON_SPEC_CORRECT_PATH
...
The reason is that the hardware filter only considers the privilege level applicable to the branch target. Extend software filtering to also validate the branch-from addresses against br_sel, so that any branch record whose branch-from address is in the kernel is dropped when PERF_SAMPLE_BRANCH_USER is requested.
--- arch/x86/events/amd/lbr.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
arch/x86/events/amd/lbr.c +2 -1
@@ -124,7 +124,8 @@ static void amd_pmu_lbr_filter(void) }/* If type does not correspond, then discard */ -if (type ==X86_BR_NONE || (br_sel & type) != type) { +if (type ==X86_BR_NONE || (br_sel & type) != type || + (!(br_sel &X86_BR_KERNEL ) &&kernel_ip (cpuc->lbr_entries[i].from))) { cpuc->lbr_entries[i].from =0 ;/* mark invalid */ compress = true; }
Greg Kroah-Hartman
maintainerPATCH 762/1067 batman-adv: gw: acquire ethernet header only after skb realloc
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 77880a3be88d378d60cc1e8f8ec70430e2ed0518 upstream.
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free.
--- net/batman-adv/gateway_client.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/batman-adv/gateway_client.c +2 -1
@@ -693,12 +693,13 @@ bool batadv_gw_out_of_range(struct batadstruct batadv_gw_node *gw_node =NULL ;struct batadv_gw_node *curr_gw =NULL ;struct batadv_neigh_ifinfo *curr_ifinfo, *old_ifinfo; -struct ethhdr *ethhdr = (struct ethhdr *)skb->data; +struct ethhdr *ethhdr;bool out_of_range = false;u8 curr_tq_avg;unsigned short vid; vid =batadv_get_vid (skb,0 ); + ethhdr = (struct ethhdr *)skb->data;if (is_multicast_ether_addr (ethhdr->h_dest)) goto out;
Greg Kroah-Hartman
maintainerPATCH 763/1067 batman-adv: access unicast_ttvn skb->data only after skb realloc
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 7141990add3f75436f2933cb310654cad3b1e3e9 upstream.
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free.
This was done correctly for the ethernet header but missed for the unicast_packet pointer.
--- net/batman-adv/routing.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/batman-adv/routing.c +1 -1
@@ -855,8 +855,8 @@ static bool batadv_check_unicast_ttvn(stif (skb_cow (skb,sizeof (*unicast_packet)) <0 )return false; - unicast_packet = (struct batadv_unicast_packet *)skb->data; vid =batadv_get_vid (skb, hdr_len); + unicast_packet = (struct batadv_unicast_packet *)skb->data; ethhdr = (struct ethhdr *)(skb->data + hdr_len);/* do not reroute multicast frames in a unicast header */
Greg Kroah-Hartman
maintainerPATCH 764/1067 batman-adv: dat: acquire ARP hw source only after skb realloc
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 48067b2ae4504500a7093d9e1e16b42e70330480 upstream.
The pskb_may_pull() called by batadv_get_vid() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free.
--- net/batman-adv/distributed-arp-table.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
net/batman-adv/distributed-arp-table.c +4 -1
@@ -1758,6 +1758,7 @@ void batadv_dat_snoop_incoming_dhcp_ack(struct ethhdr *ethhdr;__be32 ip_src, yiaddr;unsigned short vid; +int hdr_size_tmp;__be16 proto;u8 *hw_src;
@@ -1774,8 +1775,10 @@ void batadv_dat_snoop_incoming_dhcp_ack(if (!batadv_dat_check_dhcp_ack (skb, proto, &ip_src, chaddr, &yiaddr))return ; + hdr_size_tmp = hdr_size; + vid =batadv_dat_get_vid (skb, &hdr_size_tmp); + ethhdr = (struct ethhdr *)(skb->data + hdr_size); hw_src = ethhdr->h_source; - vid =batadv_dat_get_vid (skb, &hdr_size);batadv_dat_entry_add (bat_priv, yiaddr, chaddr, vid);batadv_dat_entry_add (bat_priv, ip_src, hw_src, vid);
Greg Kroah-Hartman
maintainerPATCH 765/1067 batman-adv: bla: reacquire gw address after skb realloc
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit cdf3b5af2bc4431e58629e8ad2086b1e9185c761 upstream.
The pskb_may_pull() called by batadv_bla_is_backbone_gw() could reallocate the buffer behind the skb. Variables which were pointing to the old buffer need to be reassigned to avoid an use-after-free.
--- net/batman-adv/routing.c | 1 + 1 file changed, 1 insertion(+)
net/batman-adv/routing.c +1 -0
@@ -1035,6 +1035,7 @@ int batadv_recv_unicast_packet(struct sk hdr_size);batadv_orig_node_put (orig_node_gw);if (is_gw) { + orig_addr_gw =eth_hdr (skb)->h_source;batadv_dbg (BATADV_DBG_BLA , bat_priv,"%s(): Dropped unicast pkt received from another backbone gw %pM.\n" , __func__, orig_addr_gw);
Greg Kroah-Hartman
maintainerPATCH 766/1067 batman-adv: dat: ensure accessible eth_hdr proto field
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 26560c4a03dc4d607331600c187f59ab2df5f341 upstream.
When batadv_get_vid() accesses the proto field of the ethernet header, it is not checking if the data itself is accessible. The caller is responsible for it. But in contrast to other call sites, batadv_dat_get_vid() and its caller didn't make sure this is true. This could have caused an out-of-bounds access.
--- net/batman-adv/distributed-arp-table.c | 23 +++++++++++++++++++++++ net/batman-adv/main.c | 3 +++ 2 files changed, 26 insertions(+)
net/batman-adv/distributed-arp-table.c +23 -0
@@ -1077,6 +1077,9 @@ out:* @skb: the buffer containing the packet to extract the VID from * @hdr_size: the size of the batman-adv header encapsulating the packet * +* The caller must ensure that at least @hdr_size + ETH_HLEN bytes are +* accessible after skb->data. +* * Return: If the packet embedded in the skb is vlan tagged this function * returns the VID with the BATADV_VLAN_HAS_TAG flag. Otherwise BATADV_NO_FLAGS * is returned.
@@ -1159,6 +1162,10 @@ bool batadv_dat_snoop_outgoing_arp_requeif (!atomic_read (&bat_priv->distributed_arp_table)) goto out; +/* first, find out the vid. */ +if (!pskb_may_pull (skb, hdr_size +ETH_HLEN )) + goto out; + vid =batadv_dat_get_vid (skb, &hdr_size); type =batadv_arp_get_type (bat_priv, skb, hdr_size);
@@ -1254,6 +1261,10 @@ bool batadv_dat_snoop_incoming_arp_requeif (!atomic_read (&bat_priv->distributed_arp_table)) goto out; +/* first, find out the vid. */ +if (!pskb_may_pull (skb, hdr_size +ETH_HLEN )) + goto out; + vid =batadv_dat_get_vid (skb, &hdr_size); type =batadv_arp_get_type (bat_priv, skb, hdr_size);
@@ -1316,6 +1327,10 @@ void batadv_dat_snoop_outgoing_arp_replyif (!atomic_read (&bat_priv->distributed_arp_table))return ; +/* first, find out the vid. */ +if (!pskb_may_pull (skb, hdr_size +ETH_HLEN )) +return ; + vid =batadv_dat_get_vid (skb, &hdr_size); type =batadv_arp_get_type (bat_priv, skb, hdr_size);
@@ -1364,6 +1379,10 @@ bool batadv_dat_snoop_incoming_arp_replyif (!atomic_read (&bat_priv->distributed_arp_table)) goto out; +/* first, find out the vid. */ +if (!pskb_may_pull (skb, hdr_size +ETH_HLEN )) + goto out; + vid =batadv_dat_get_vid (skb, &hdr_size); type =batadv_arp_get_type (bat_priv, skb, hdr_size);
@@ -1818,6 +1837,10 @@ bool batadv_dat_drop_broadcast_packet(stif (batadv_forw_packet_is_rebroadcast (forw_packet)) goto out; +/* first, find out the vid. */ +if (!pskb_may_pull (forw_packet->skb, hdr_size +ETH_HLEN )) + goto out; + vid =batadv_dat_get_vid (forw_packet->skb, &hdr_size); type =batadv_arp_get_type (bat_priv, forw_packet->skb, hdr_size);
net/batman-adv/main.c +3 -0
@@ -618,6 +618,9 @@ __be32 batadv_skb_crc32(struct sk_buff ** @skb: the buffer containing the packet * @header_len: length of the batman header preceding the ethernet header * +* The caller must ensure that at least @header_len + ETH_HLEN bytes are +* accessible after skb->data. +* * Return: VID with the BATADV_VLAN_HAS_TAG flag when the packet embedded in the * skb is vlan tagged. Otherwise BATADV_NO_FLAGS. */
Greg Kroah-Hartman
maintainerPATCH 767/1067 batman-adv: dat: fix tie-break for candidate selection
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 98052bdaf6ac1639a63ffc10244eeeab1f62ed2b upstream.
The original version of the candidate selection for DAT attempted to compare both candidate and max_orig_node to identify which has the smaller MAC address. This comparison is required as tie-break when a hash collision happened.
But the used function returned 0 when the function was not equal and a non-zero value when it was equal. As result, the actually selected node was dependent on the order of entries in the orig_hash and not actually on the mac addresses. The last originator in the hash collision would always win.
To have a proper ordering, it must diff the actual MAC address bytes and reject the candidate when the diff is not smaller than 0.
--- net/batman-adv/distributed-arp-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/batman-adv/distributed-arp-table.c +1 -1
@@ -546,7 +546,7 @@ static bool batadv_is_orig_node_eligible* the one with the lowest address */ if (tmp_max == max && max_orig_node && -batadv_compare_eth (candidate->orig, max_orig_node->orig)) +memcmp (candidate->orig, max_orig_node->orig,ETH_ALEN ) >=0 ) goto out; ret = true;
Greg Kroah-Hartman
maintainerPATCH 768/1067 batman-adv: tt: avoid request storms during pending request
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 27c7d40008231ae4140d35501b60087a9de2d2c3 upstream.
batadv_send_tt_request() allocates a tt_req_node when none exists for the destination originator node. This should prevent that a multiple TT requests are send at the same time to an originator.
But if allocation of the send buffer failed, this request must be cleaned up again. But indicator for such a failure is "ret == false". But the actual implementation is checking for "ret == true".
The check must be inverted to not loose the information about the TT request directly after it was attempted to be sent out. This should avoid potential request storms.
--- net/batman-adv/translation-table.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/batman-adv/translation-table.c +1 -1
@@ -3032,7 +3032,7 @@ static bool batadv_send_tt_request(struc out:batadv_hardif_put (primary_if); -if (ret && tt_req_node) { +if (!ret && tt_req_node) {spin_lock_bh (&bat_priv->tt.req_list_lock);if (!hlist_unhashed (&tt_req_node->list)) {hlist_del_init (&tt_req_node->list);
Greg Kroah-Hartman
maintainerPATCH 769/1067 batman-adv: fix VLAN priority offset
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit fdb3be00ba4dafa313e699d6b5b90d13f22f3f25 upstream.
The batadv_skb_set_priority() receives an SKB with the inner ethernet header at position "offset". When it tries to extract the IPv4 and IPv6 header, it needs to skip the ethernet header to get access to the IP header.
But for VLAN header, it performs the access with the struct vlan_ethhdr. This struct contains both both the ethernet header and the VLAN header. It is therefore incorrect to skip over the whole vlan_ethhdr size to get access to the vlan_ethhdr.
--- net/batman-adv/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/batman-adv/main.c +1 -1
@@ -375,7 +375,7 @@ void batadv_skb_set_priority(struct sk_bswitch (ethhdr->h_proto) {case htons (ETH_P_8021Q ): - vhdr =skb_header_pointer (skb, offset +sizeof (*vhdr), + vhdr =skb_header_pointer (skb, offset,sizeof (*vhdr), &vhdr_tmp);if (!vhdr)return ;
Greg Kroah-Hartman
maintainerPATCH 770/1067 batman-adv: frag: free unfragmentable packet
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 6b628425aed49a1c7a4ffc997583840fc582d32b upstream.
The caller of batadv_frag_send_packet() assume that the skb provided to the function are always consumed. But the pre-check for an empty payload or the zero fragment size returned an error without any further actions.
A failed pre-check must use the same error handling code as the rest of the function.
--- net/batman-adv/fragmentation.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
net/batman-adv/fragmentation.c +4 -2
@@ -522,8 +522,10 @@ int batadv_frag_send_packet(struct sk_bu mtu = min_t(unsigned int, mtu, BATADV_FRAG_MAX_FRAG_SIZE); max_fragment_size = mtu - header_size; -if (skb->len ==0 || max_fragment_size ==0 ) -return -EINVAL ; +if (skb->len ==0 || max_fragment_size ==0 ) { + ret = -EINVAL ; + goto free_skb; + } num_fragments = (skb->len -1 ) / max_fragment_size +1 ; max_fragment_size = (skb->len -1 ) / num_fragments +1 ;
Greg Kroah-Hartman
maintainerPATCH 771/1067 batman-adv: frag: fix primary_if leak on failed linearization
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 353d2c1d5492e53ae34f490a84494124dc3d3531 upstream.
If the skb has a frag_list, it must be linearized before it can be split using skb_split(). But when this step failed, it must not only free the skb but also take care of the reference to the already found primary_if.
--- net/batman-adv/fragmentation.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/batman-adv/fragmentation.c +1 -1
@@ -551,7 +551,7 @@ int batadv_frag_send_packet(struct sk_bu*/ if (skb_has_frag_list (skb) &&__skb_linearize (skb)) { ret = -ENOMEM ; - goto free_skb; + goto put_primary_if; }/* Create one header to be copied to all fragments */
Greg Kroah-Hartman
maintainerPATCH 772/1067 batman-adv: tt: prevent TVLV OOB check overflow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 7a581d9aaba8c82bd6177fa36b2588eea77f6e2b upstream.
A TT unicast TVLV contains the number of VLANs stored in it. This number is an u16 and gets multiplied by the size of the struct batadv_tvlv_tt_vlan_data (8 bytes). The size can therefore overflow the u16 used to store the tt_vlan_len. All additional safety checks to prevent out-of-bounds access of the TVLV buffer are invalid due to this overflow.
Using size_t prevents this overflow and ensures that the safety checks compare against the actual buffer requirements.
--- net/batman-adv/translation-table.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
net/batman-adv/translation-table.c +2 -1
@@ -4101,7 +4101,8 @@ static int batadv_tt_tvlv_unicast_handle u16 tvlv_value_len) {struct batadv_tvlv_tt_data *tt_data; -u16 tt_vlan_len, tt_num_entries; +u16 tt_num_entries; +size_t tt_vlan_len;char tt_flag;bool ret;
Greg Kroah-Hartman
maintainerPATCH 773/1067 mfd: tps6586x: Fix OF node refcount
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bartosz Golaszewski <[email protected]>
commit 3001ed2b4e06da2276c42ace6551617065a5b1f9 upstream.
Platform devices created with platform_device_alloc() call platform_device_release() when the last reference to the device's kobject is dropped. This function calls of_node_put() unconditionally. This works fine for devices created with platform_device_register_full() but users of the split approach (platform_device_alloc() + platform_device_add()) must bump the reference of the of_node they assign manually. Add the missing call to of_node_get().
--- drivers/mfd/tps6586x.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mfd/tps6586x.c +1 -1
@@ -399,7 +399,7 @@ static int tps6586x_add_subdevs(struct t pdev->dev.parent = tps6586x->dev; pdev->dev.platform_data = subdev->platform_data; - pdev->dev.of_node = subdev->of_node; + pdev->dev.of_node =of_node_get (subdev->of_node); ret =platform_device_add (pdev);if (ret) {
Greg Kroah-Hartman
maintainerPATCH 774/1067 Bluetooth: SCO: fix sleeping under spinlock in sco_conn_ready
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
commit b819db93d73f4593636299e229914052b89e3ef2 upstream.
sco_conn_ready calls sleeping functions under conn->lock spinlock.
The critical section can be reduced: conn->hcon is modified only with hdev->lock held. It is guaranteed to be held in sco_conn_ready, so conn->lock is not needed to guard it.
Move taking conn->lock after lock_sock(parent). This also follows the lock ordering lock_sock() > conn->lock elsewhere in the file.
--- net/bluetooth/sco.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-)
net/bluetooth/sco.c +9 -11
@@ -1328,26 +1328,24 @@ static void sco_conn_ready(struct sco_co sk->sk_state_change (sk);release_sock (sk); }else { -sco_conn_lock (conn); - -if (!conn->hcon) { -sco_conn_unlock (conn); +if (!conn->hcon)return ; - } + +lockdep_assert_held (&conn->hcon->hdev->lock); parent =sco_get_sock_listen (&conn->hcon->src); -if (!parent) { -sco_conn_unlock (conn); +if (!parent)return ; - }lock_sock (parent); +sco_conn_lock (conn); + sk =sco_sock_alloc (sock_net (parent),NULL ,BTPROTO_SCO ,GFP_ATOMIC ,0 );if (!sk) { -release_sock (parent);sco_conn_unlock (conn); +release_sock (parent);return ; }
@@ -1367,9 +1365,9 @@ static void sco_conn_ready(struct sco_co/* Wake up parent */ parent->sk_data_ready (parent); -release_sock (parent); -sco_conn_unlock (conn); + +release_sock (parent); } }
Greg Kroah-Hartman
maintainerPATCH 775/1067 Bluetooth: SCO: hold sk properly in sco_conn_ready
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pauli Virtanen <[email protected]>
commit 4e37f6452d586b95c346a9abdd2fb80b67794f39 upstream.
sk deref in sco_conn_ready must be done either under conn->lock, or holding a refcount, to avoid concurrent close. conn->sk and parent sk is currently accessed without either, and without checking parent->sk_state:
[Task 1] [Task 2]
sco_sock_release
sco_conn_ready
sk = conn->sk
lock_sock(sk)
conn->sk = NULL
lock_sock(sk)
release_sock(sk)
sco_sock_kill(sk)
UAF on sk deref
and similarly for access to sco_get_sock_listen() return value.
Fix possible UAF by holding sk refcount in sco_conn_ready() and making sco_get_sock_listen() increase refcount. Also recheck after lock_sock that the socket is still valid. Adjust conn->sk locking so it's protected also by lock_sock() of the associated socket if any.
--- net/bluetooth/sco.c | 44 ++++++++++++++++++++++++++++++++------------ 1 file changed, 32 insertions(+), 12 deletions(-)
net/bluetooth/sco.c +32 -12
@@ -410,9 +410,13 @@ static struct sock *sco_get_sock_listen( sk1 = sk; } + sk = sk ? sk : sk1; +if (sk) +sock_hold (sk); +read_unlock (&sco_sk_list.lock); -return sk ? sk : sk1; +return sk; }static void sco_sock_destruct (struct sock *sk)
@@ -452,11 +456,13 @@ static void sco_sock_kill(struct sock *sBT_DBG ("sk %p state %d" , sk, sk->sk_state);/* Sock is dead, so set conn->sk to NULL to avoid possible UAF */ +lock_sock (sk);if (sco_pi (sk)->conn) {sco_conn_lock (sco_pi (sk)->conn);sco_pi (sk)->conn->sk =NULL ;sco_conn_unlock (sco_pi (sk)->conn); } +release_sock (sk);/* Kill poor orphan */ bt_sock_unlink (&sco_sk_list, sk);
@@ -1316,17 +1322,28 @@ static int sco_sock_release(struct sockestatic void sco_conn_ready (struct sco_conn *conn) { -struct sock *parent; -struct sock *sk = conn->sk; +struct sock *parent, *sk; + +sco_conn_lock (conn); + sk =sco_sock_hold (conn); +sco_conn_unlock (conn);BT_DBG ("conn %p" , conn);if (sk) {lock_sock (sk); -sco_sock_clear_timer (sk); - sk->sk_state =BT_CONNECTED ; - sk->sk_state_change (sk); + +/* conn->sk may have become NULL if racing with sk close, but +* due to held hdev->lock, it can't become different sk. +*/ +if (conn->sk) { +sco_sock_clear_timer (sk); + sk->sk_state =BT_CONNECTED ; + sk->sk_state_change (sk); + } +release_sock (sk); +sock_put (sk); }else {if (!conn->hcon)return ;
@@ -1341,13 +1358,15 @@ static void sco_conn_ready(struct sco_cosco_conn_lock (conn); +/* hdev->lock guarantees conn->sk == NULL still here */ + +if (parent->sk_state !=BT_LISTEN ) + goto release; + sk =sco_sock_alloc (sock_net (parent),NULL ,BTPROTO_SCO ,GFP_ATOMIC ,0 ); -if (!sk) { -sco_conn_unlock (conn); -release_sock (parent); -return ; - } +if (!sk) + goto release;sco_sock_init (sk, parent);
@@ -1365,9 +1384,10 @@ static void sco_conn_ready(struct sco_co/* Wake up parent */ parent->sk_data_ready (parent); +release:sco_conn_unlock (conn); -release_sock (parent); +sock_put (parent); } }
Greg Kroah-Hartman
maintainerPATCH 776/1067 jbd2: fix integer underflow in jbd2_journal_initialize_fast_commit()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Junrui Luo <[email protected]>
commit 289a2ca0c9b7eae74f93fc213b0b971669b8683d upstream.
jbd2_journal_initialize_fast_commit() validates journal capacity by checking (journal->j_last - num_fc_blks < JBD2_MIN_JOURNAL_BLOCKS). Both j_last and num_fc_blks are unsigned, so when num_fc_blks exceeds j_last the subtraction wraps to a large value, bypassing the bounds check.
The resulting underflow corrupts j_last, j_fc_first, and j_free, leading to journal abort.
Fix by checking num_fc_blks against j_last before the subtraction, returning -EFSCORRUPTED.
--- fs/jbd2/journal.c | 2 ++ 1 file changed, 2 insertions(+)
fs/jbd2/journal.c +2 -0
@@ -2289,6 +2289,8 @@ jbd2_journal_initialize_fast_commit(jourunsigned long long num_fc_blks; num_fc_blks =jbd2_journal_get_num_fc_blks (sb); +if (num_fc_blks > journal->j_last) +return -EFSCORRUPTED ;if (journal->j_last - num_fc_blks <JBD2_MIN_JOURNAL_BLOCKS )return -ENOSPC ;
Greg Kroah-Hartman
maintainerPATCH 777/1067 nvdimm/btt: Free arenas on btt_init() error paths
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 1a6b6442a982d0ca5fb6a1a39b6f6dfd760eda57 upstream.
The arenas allocated by discover_arenas() or create_arenas() are not freed on some error paths in btt_init(). This leaks memory when BTT initialization fails.
Call free_arenas() from the affected error paths to release the allocations.
[ as: commit message and log edits ]
--- drivers/nvdimm/btt.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/nvdimm/btt.c +7 -4
@@ -1607,7 +1607,7 @@ static struct btt *btt_init(struct nd_btif (btt->init_state !=INIT_READY && nd_region->ro) {dev_warn (dev,"%s is read-only, unable to init btt metadata\n" ,dev_name (&nd_region->dev)); -return NULL ; + goto err; }else if (btt->init_state !=INIT_READY ) { btt->num_arenas = (rawsize /ARENA_MAX_SIZE ) + ((rawsize %ARENA_MAX_SIZE ) ?1 :0 );
@@ -1617,25 +1617,28 @@ static struct btt *btt_init(struct nd_bt ret =create_arenas (btt);if (ret) {dev_info (dev,"init: create_arenas: %d\n" , ret); -return NULL ; + goto err; } ret =btt_meta_init (btt);if (ret) {dev_err (dev,"init: error in meta_init: %d\n" , ret); -return NULL ; + goto err; } } ret =btt_blk_init (btt);if (ret) {dev_err (dev,"init: error in blk_init: %d\n" , ret); -return NULL ; + goto err; }btt_debugfs_init (btt);return btt; +err: +free_arenas (btt); +return NULL ; }/**
Greg Kroah-Hartman
maintainerPATCH 778/1067 nvdimm/btt: Free arena sub-allocations on discover_arenas() error path
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 13fe4cd9ddd0aacb7777812328be525a11ea3fea upstream.
Memory allocated by btt_freelist_init(), btt_rtt_init(), and btt_maplocks_init() is not freed on some discover_arenas() error paths. This leaks memory when arena discovery fails.
Add the missing kfree() calls to release the allocations before returning an error.
[ as: commit message and log edits ]
--- drivers/nvdimm/btt.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/nvdimm/btt.c +3 -0
@@ -923,6 +923,9 @@ static int discover_arenas(struct btt *breturn ret; out: +kfree (arena->freelist); +kfree (arena->rtt); +kfree (arena->map_locks);kfree (arena);free_arenas (btt); out_super:
Greg Kroah-Hartman
maintainerPATCH 779/1067 lockd: Plug nlm_file leak when nlm_do_fopen() fails
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
commit f16a1513452edb532fec81e591c64c320866719c upstream.
A client can repeatedly drive nlm_do_fopen() failures by presenting file handles that the underlying export rejects. After kzalloc_obj() succeeds in nlm_lookup_file(), the freshly allocated nlm_file is not yet inserted into nlm_files[]. The nlm_do_fopen() failure path jumps to out_unlock, which releases nlm_file_mutex and returns without freeing the allocation, so each failure leaks one nlm_file.
Route the failure through out_free so kfree() runs before the function returns.
--- fs/lockd/svcsubs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/lockd/svcsubs.c +1 -1
@@ -139,7 +139,7 @@ nlm_lookup_file(struct svc_rqst *rqstp, nfserr =nlm_do_fopen (rqstp, file, mode);if (nfserr) - goto out_unlock; + goto out_free;hlist_add_head (&file->f_list, &nlm_files[hash]);
Greg Kroah-Hartman
maintainerPATCH 780/1067 lockd: Plug nlm_file refcount leak on cached nlm_do_fopen() failure
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chuck Lever <[email protected]>
commit 70a38f87bed7f0694fd07988b47b2db1e10d8df3 upstream.
The cached-file path in nlm_lookup_file() reaches the found: label unconditionally, even when nlm_do_fopen() fails. At that label *result and file->f_count are updated before the error is returned. The wrappers nlm3svc_lookup_file() and nlm4svc_lookup_file() then bail out of their switch without copying *result back to their caller, so the proc handler's local nlm_file pointer remains NULL and the cleanup path skips nlm_release_file(). The f_count increment is never released, and nlm_traverse_files() can no longer reap the file because its refcount never returns to zero between requests.
Short-circuit the cached path so neither *result nor f_count is touched when nlm_do_fopen() fails on a hashed nlm_file.
--- fs/lockd/svcsubs.c | 2 ++ 1 file changed, 2 insertions(+)
fs/lockd/svcsubs.c +2 -0
@@ -123,6 +123,8 @@ nlm_lookup_file(struct svc_rqst *rqstp,mutex_lock (&file->f_mutex); nfserr =nlm_do_fopen (rqstp, file, mode);mutex_unlock (&file->f_mutex); +if (nfserr) + goto out_unlock; goto found; }nlm_debug_print_fh ("creating file for" , &lock->fh);
Greg Kroah-Hartman
maintainerPATCH 781/1067 MIPS: ip22-gio: fix gio device memory leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 7de9a1b45f5a95b58145653c525c8fb80292d9ab upstream.
The gio device release callback was never wired up so gio devices are not freed when the last reference is dropped.
--- arch/mips/sgi-ip22/ip22-gio.c | 2 ++ 1 file changed, 2 insertions(+)
arch/mips/sgi-ip22/ip22-gio.c +2 -0
@@ -101,6 +101,8 @@ int gio_device_register(struct gio_devic { giodev->dev.bus = &gio_bus_type; giodev->dev.parent = &gio_bus; + giodev->dev.release = gio_release_dev; +return device_register (&giodev->dev); }EXPORT_SYMBOL_GPL (gio_device_register);
Greg Kroah-Hartman
maintainerPATCH 782/1067 MIPS: ip22-gio: fix kfree() of static object
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit c62cdd3e919bdf84c37ec46810f87cdb1736e822 upstream.
The gio bus root device is a statically allocated object which must not be freed by kfree() on failure to register the device or bus.
--- arch/mips/sgi-ip22/ip22-gio.c | 1 - 1 file changed, 1 deletion(-)
arch/mips/sgi-ip22/ip22-gio.c +0 -1
@@ -30,7 +30,6 @@ static struct {static void gio_bus_release (struct device *dev) { -kfree (dev); }static struct device gio_bus = {
Greg Kroah-Hartman
maintainerPATCH 783/1067 MIPS: ip22-gio: fix device reference leak in probe
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit b82930a4c5dbc5c4df39c0f93d968c239f2c6885 upstream.
The gio probe function needlessly takes a device reference which is never released and therefore prevents unbound gio devices from being freed.
--- arch/mips/sgi-ip22/ip22-gio.c | 4 ---- 1 file changed, 4 deletions(-)
arch/mips/sgi-ip22/ip22-gio.c +0 -4
@@ -133,13 +133,9 @@ static int gio_device_probe(struct devicif (!drv->probe)return error; -gio_dev_get (gio_dev); - match =gio_match_device (drv->id_table, gio_dev);if (match) error = drv->probe (gio_dev, match); -if (error) -gio_dev_put (gio_dev);return error; }
Greg Kroah-Hartman
maintainerPATCH 784/1067 MIPS: DEC: Ensure 32-bit stack location for o32 prom_printf()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maciej W. Rozycki <[email protected]>
commit 5ff79e8bdc75db51e30298a75939e2308e7658e0 upstream.
In 64-bit configurations calling any firmware entry points from a kernel thread other than the initial one will result in a situation where the stack has been placed in the XKPHYS 64-bit memory segment.
Consequently the stack pointer is no longer a 32-bit value and when the 32-bit firmware code called uses 32-bit ALU operations to manipulate the stack pointer, the calculated result is incorrect (in fact in the 64-bit MIPS ISA almost all 32-bit ALU operations will produce an unpredictable result when executed on 64-bit data) and control goes astray.
This may happen when no final console driver has been enabled in the configuration and consequently the initial console continues being used late into bootstrap, or with an upcoming change that will switch the zs driver to use a platform device, which in turn will make the console handover happen only after other kernel threads have already been started, and the kernel will hang at:
pid_max: default: 32768 minimum: 301
or somewhat later, but always before:
cblist_init_generic: Setting adjustable number of callback queues.
has been printed.
It seems that only the prom_printf() entry point is affected. Of all the other entry points wired only rex_slot_address() and rex_gettcinfo() are called from a kernel thread other than the initial one, specifically kernel_init(), and they are leaf functions that do no business with the stack, having worked with no issue ever since 64-bit support was added for the platform back in 2002.
To address this issue then, arrange for the stack to be switched in the o32 wrapper as required for prom_printf() only, by supplying call_o32() with a pointer to a chunk of initdata space, which is placed in the CKSEG0 32-bit compatibility segment, observing that prom_printf() is only called from console output handler and therefore with the console lock held, implying no need for this code to be reentrant.
Other firmware entry points may be called with interrupts enabled and no lock held, and may therefore require that call_o32() be reentrant. They trigger no issue at this point and "if it ain't broke, don't fix it," so just leave them alone.
--- arch/mips/dec/prom/init.c | 6 +++++- arch/mips/include/asm/dec/prom.h | 15 +++++++++++++-- 2 files changed, 18 insertions(+), 3 deletions(-)
arch/mips/dec/prom/init.c +5 -1
@@ -3,7 +3,7 @@* init.c: PROM library initialisation code. * * Copyright (C) 1998 Harald Koerfgen -* Copyright (C) 2002, 2004 Maciej W. Rozycki +* Copyright (C) 2002, 2004, 2026 Maciej W. Rozycki */ #include <linux/init.h> #include <linux/kernel.h>
@@ -20,6 +20,10 @@#include <asm/dec/prom.h> +#ifdef CONFIG_64BIT +unsigned long o32_stk[O32_STK_SIZE ]__initdata = {0 }; +#endif +int (*__rex_bootinit)(void );int (*__rex_bootread)(void );int (*__rex_getbitmap)(memmap *);
arch/mips/include/asm/dec/prom.h +13 -2
@@ -4,7 +4,7 @@* * DECstation PROM interface. * -* Copyright (C) 2002 Maciej W. Rozycki +* Copyright (C) 2002, 2026 Maciej W. Rozycki * * Based on arch/mips/dec/prom/prom.h by the Anonymous. */
@@ -97,6 +97,17 @@ extern int (*__pmax_close)(int);#ifdef CONFIG_64BIT +#define O32_STK_SIZE 512 +extern unsigned long o32_stk[]; + +/* Switch the stack if outside the 32-bit address space. */ +static inline unsigned long *o32_get_stk (void ) +{ +long fp = (long )__builtin_frame_address (0 ); + +return fp != (int )fp ? o32_stk +O32_STK_SIZE :NULL ; +} +/* * On MIPS64 we have to call PROM functions via a helper * dispatcher to accommodate ABI incompatibilities.
@@ -128,7 +139,7 @@ int __DEC_PROM_O32(_prom_printf, (int (*#define prom_getchar () _prom_getchar(__prom_getchar, NULL)#define prom_getenv (x) _prom_getenv(__prom_getenv, NULL, x) -#define prom_printf(x...) _prom_printf(__prom_printf, NULL, x) +#define prom_printf(x...) _prom_printf(__prom_printf, o32_get_stk(), x)#else /* !CONFIG_64BIT */
Greg Kroah-Hartman
maintainerPATCH 785/1067 power: supply: cpcap-battery: Fix missing nvmem_device_put() causing reference leak
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ma Ke <[email protected]>
commit a2c14ff63e0e02e3c832385e523e9cc81301171c upstream.
In cpcap_battery_detect_battery_type(), the reference to an nvmem device obtained via nvmem_device_find() is not released with nvmem_device_put() on the success or read-failure paths, causing a permanent reference leak. The driver’s retry logic on subsequent battery property reads can compound this leak, preventing the nvmem device from ever being freed.
Found by code review.
--- drivers/power/supply/cpcap-battery.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/power/supply/cpcap-battery.c +7 -4
@@ -415,10 +415,13 @@ static void cpcap_battery_detect_batteryif (IS_ERR_OR_NULL (nvmem)) { ddata->check_nvmem = true;dev_info_once (ddata->dev,"Can not find battery nvmem device. Assuming generic lipo battery\n" ); - }else if (nvmem_device_read (nvmem,2 ,1 , &battery_id) <0 ) { - battery_id =0 ; - ddata->check_nvmem = true; -dev_warn (ddata->dev,"Can not read battery nvmem device. Assuming generic lipo battery\n" ); + }else { +if (nvmem_device_read (nvmem,2 ,1 , &battery_id) <0 ) { + battery_id =0 ; + ddata->check_nvmem = true; +dev_warn (ddata->dev,"Can not read battery nvmem device. Assuming generic lipo battery\n" ); + } +nvmem_device_put (nvmem); }switch (battery_id) {
Greg Kroah-Hartman
maintainerPATCH 786/1067 fs/ntfs3: fix syncing wrong inode on DIRSYNC cross-directory rename
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit 932fa0c1496286e39e14e27194c1ee7c2181629f upstream.
In ntfs3_rename(), when IS_DIRSYNC(new_dir) is true, the code syncs the renamed file inode instead of the target directory new_dir:
if (IS_DIRSYNC(new_dir))
ntfs_sync_inode(inode); /* should be new_dir */
DIRSYNC requires that directory metadata changes are written to disk synchronously. Since new_dir was modified (a new directory entry was added), it is new_dir that must be synced to satisfy the guarantee, not the renamed file itself.
This bug has existed since the initial ntfs3 implementation and was carried through the refactoring in commit 78ab59fee07f ("fs/ntfs3: Rework file operations").
Fix by syncing new_dir instead of inode.
--- fs/ntfs3/namei.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ntfs3/namei.c +1 -1
@@ -333,7 +333,7 @@ static int ntfs_rename(struct user_namesntfs_sync_inode (dir);if (IS_DIRSYNC (new_dir)) -ntfs_sync_inode (inode); +ntfs_sync_inode (new_dir); }ni_unlock (ni);
Greg Kroah-Hartman
maintainerPATCH 787/1067 fs/ntfs3: bound DeleteIndexEntryAllocation memmove length
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
commit fc4626bb3656362de8b0ecd56605d47a19ec3518 upstream.
In do_action()'s DeleteIndexEntryAllocation case, e->size comes from an on-disk INDEX_BUFFER entry. When e->size makes e + e->size point past hdr + hdr->used,PtrOffset(e1, Add2Ptr(hdr, used)) returns a negative ptrdiff_t that is silently cast to a quasi-infinite size_t when passed to memmove(). The memmove then walks past the destination buffer.
The sibling DeleteIndexEntryRoot case at fslog.c:3540-3543 already carries the corresponding guard:
if (PtrOffset(e1, Add2Ptr(hdr, used)) < esize ||
Add2Ptr(e, esize) > Add2Ptr(lrh, rec_len) ||
used + esize > le32_to_cpu(hdr->total)) {
goto dirty_vol;
}Apply the same shape to the allocation-path case. Also reject esize == 0: memmove(e, e, ...) is a no-op and leaves hdr->used unchanged, hiding a malformed entry from the existing check_index_header() walk.
Reproduced under UML+KASAN on mainline 8d90b09e6741 by mounting a crafted NTFS image: the unguarded memmove takes a length of 0xffffffffffffff00 and the kernel oopses in memmove+0x81/0x1a0 on the do_action+0x36a2 frame.
--- fs/ntfs3/fslog.c | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-)
fs/ntfs3/fslog.c +15 -1
@@ -3577,9 +3577,23 @@ move_data: } e1 =Add2Ptr (e, esize); - nsize = esize; used =le32_to_cpu (hdr->used); +/* +* Reject crafted entries whose e->size makes e + esize +* point past the INDEX_HDR's used boundary. Without this, +* PtrOffset(e1, hdr + used) underflows to a quasi-infinite +* size_t when fed to the memmove() below. +* +* Also reject esize == 0: memmove(e, e, ...) is a no-op and +* leaves hdr->used unchanged, masking the crafted entry. +*/ +if (!esize ||Add2Ptr (e, esize) >Add2Ptr (hdr, used) || +PtrOffset (e1,Add2Ptr (hdr, used)) < esize) + goto dirty_vol; + + nsize = esize; +memmove (e, e1,PtrOffset (e1,Add2Ptr (hdr, used))); hdr->used =cpu_to_le32 (used - nsize);
Greg Kroah-Hartman
maintainerPATCH 788/1067 fs/ntfs3: bound copy_lcns dp->page_lcns[] index in analysis pass
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 5e7b598660cfa8e5af172cf4c65cffc126333307 upstream.
In log_replay()'s analysis pass, after find_dp() returns a valid DIR_PAGE_ENTRY for the (target_attr, target_vcn) tuple, the copy_lcns block walks lrh->lcns_follow further entries:
t16 = le16_to_cpu(lrh->lcns_follow);
for (i = 0; i < t16; i++) {
size_t j = (size_t)(le64_to_cpu(lrh->target_vcn) -
le64_to_cpu(dp->vcn));
dp->page_lcns[j + i] = lrh->page_lcns[i];
}find_dp() only validates that target_vcn falls within [dp->vcn, dp->vcn + dp->lcns_follow), i.e., that the FIRST cluster is covered. The walk through the further entries is not bounded against dp->lcns_follow. For a malformed LRH where target_vcn = dp->vcn + dp->lcns_follow - 1 and lrh->lcns_follow > 1, the i > 0 writes overflow the dp's allocated page_lcns[] array.
Add the missing j + lrh->lcns_follow <= dp->lcns_follow guard.
Reproduced under UML+KASAN on mainline 8d90b09e6741 as a slab-out-of-bounds write of size 8 from log_replay+0x68d4 on the mount path.
This is distinct from Pavitra Jha's 2026-05-02 patch ("fs/ntfs3: validate lcns_follow in log_replay conversion", <[email protected]>) which addresses the separate version-0 dirty-page-table conversion path's memmove(&dp->vcn, ...) call. The two fixes are complementary; both should land.
[[email protected]: clang-formatted the changes, fixed conflicts]
--- fs/ntfs3/fslog.c | 46 +++++++++++++++++++++++++++++----------------- 1 file changed, 29 insertions(+), 17 deletions(-)
fs/ntfs3/fslog.c +29 -17
@@ -3368,8 +3368,8 @@ move_data:if (run_get_highest_vcn (le64_to_cpu (attr->nres.svcn),attr_run (attr), -le32_to_cpu (attr->size) - -le16_to_cpu (attr->nres.run_off), +le32_to_cpu (attr->size) - +le16_to_cpu (attr->nres.run_off), &t64)) { goto dirty_vol; }
@@ -4563,22 +4563,34 @@ copy_lcns:* whole routine a loop, case Lcns do not fit below. */ t16 =le16_to_cpu (lrh->lcns_follow); - t32 =le32_to_cpu (dp->lcns_follow); -if (le64_to_cpu (lrh->target_vcn) <le64_to_cpu (dp->vcn)) { - err = -EINVAL ; - goto out; - } - -for (i =0 ; i < t16; i++) { -size_t j = (size_t )(le64_to_cpu (lrh->target_vcn) - -le64_to_cpu (dp->vcn)); -if (j >= t32 || i >= t32 - j) { - err = -EINVAL ; - goto out; - } - dp->page_lcns[j + i] = lrh->page_lcns[i]; - } + t32 =le32_to_cpu (dp->lcns_follow); +if (le64_to_cpu (lrh->target_vcn) <le64_to_cpu (dp->vcn)) { + err = -EINVAL ; + goto out; + } + +/* +* find_dp() only validates that target_vcn is the first +* cluster covered by dp. The walk through lrh->lcns_follow +* further entries must stay within the allocated +* dp->page_lcns[] array, which is sized by dp->lcns_follow. +*/ +if (le64_to_cpu (lrh->target_vcn) -le64_to_cpu (dp->vcn) + t16 > +le32_to_cpu (dp->lcns_follow)) { + err = -EINVAL ; + log->set_dirty = true; + goto out; + } +for (i =0 ; i < t16; i++) { +size_t j = (size_t )(le64_to_cpu (lrh->target_vcn) - +le64_to_cpu (dp->vcn)); +if (j >= t32 || i >= t32 - j) { + err = -EINVAL ; + goto out; + } + dp->page_lcns[j + i] = lrh->page_lcns[i]; + } goto next_log_record_analyze;case DeleteDirtyClusters: {
Greg Kroah-Hartman
maintainerPATCH 789/1067 fs/ntfs3: bound attr_off in UpdateResidentValue against data_off
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
commit d1570c48f49a693974d000251030370ee2e83539 upstream.
In do_action()'s UpdateResidentValue case (fslog.c:3307), lrh->attr_off and lrh->redo_len come from the on-disk LRH. When they satisfy aoff + dlen < attr->res.data_off, the assignment
attr->res.data_size = cpu_to_le32(aoff + dlen - data_off);
underflows to ~4 GiB (e.g. 0xFFFFFFF9 when aoff=0x10, dlen=1, data_off=0x18). Subsequent code that reads attr->res.data_size to walk the resident attribute payload would then read up to 4 GiB past the 1024-byte MFT record allocation.
The existing mi_enum_attr() defense in fs/ntfs3/record.c:287 catches the corrupted data_size on the next attribute walk and fails the mount, but only on the path that walks all attributes. A read site that picks an attribute by name and reads its data_size without re-validating is not covered. Validate aoff against data_off and asize at the source.
Reproduced under UML+KASAN on mainline 8d90b09e6741 via pr_warn-only probe: with aoff=0x10 and data_off=0x18, the post-assignment data_size is 0xfffffff9 (mount then fails at -22 from mi_enum_attr).
--- fs/ntfs3/fslog.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
fs/ntfs3/fslog.c +11 -0
@@ -3316,6 +3316,17 @@ skip_load_parent: nsize =ALIGN (nsize,8 ); data_off =le16_to_cpu (attr->res.data_off); +/* +* aoff comes from the on-disk lrh->attr_off. Forbid +* writes that begin below the resident attribute's +* data_off (which would overwrite the resident header), +* and forbid aoff + dlen < data_off, which would make +* the data_size assignment below underflow to ~4 GiB. +*/ +if (aoff < data_off || aoff + dlen < data_off || + aoff + dlen > asize) + goto dirty_vol; +if (nsize < asize) {memmove (Add2Ptr (attr, aoff), data, dlen); data =NULL ;// To skip below memmove().
Greg Kroah-Hartman
maintainerPATCH 790/1067 fs/ntfs3: validate lcns_follow in log_replay conversion
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Konstantin Komarov <[email protected]>
commit 6a4c53a2e26a865565bd6a460961e8d6fcb32329 upstream.
log_replay() converts DIR_PAGE_ENTRY_32 records into DIR_PAGE_ENTRY records when replaying version 0 restart tables.
During this conversion, the memmove() length is derived directly from the on-disk lcns_follow field:
memmove(&dp->vcn, &dp0->vcn_low, 2 * sizeof(u64) + le32_to_cpu(dp->lcns_follow) * sizeof(u64));
check_rstbl() validates restart table structure, but does not constrain per-entry lcns_follow values relative to the entry size. A malformed filesystem image can provide an oversized lcns_follow value, causing the conversion memmove() to access memory beyond the bounds of the allocated restart table buffer.
The same field is later used to bound iteration over page_lcns[], so validating lcns_follow during conversion also prevents downstream out-of-bounds access from the same malformed metadata.
Compute the maximum valid lcns_follow from the already-validated restart table entry size and reject entries that exceed this bound. Reuse the existing t16/t32 scratch variables already declared in log_replay() to avoid introducing new declarations.
--- fs/ntfs3/fslog.c | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-)
fs/ntfs3/fslog.c +16 -3
@@ -4265,13 +4265,26 @@ check_dirty_page_table:if (rst->major_ver) goto end_conv_1; + t16 =le16_to_cpu (dptbl->size); +if (t16 <sizeof (struct DIR_PAGE_ENTRY )) { + log->set_dirty = true; + goto out; + } + + t32 = (t16 -sizeof (struct DIR_PAGE_ENTRY )) /sizeof (u64); + dp =NULL ;while ((dp =enum_rstbl (dptbl, dp))) {struct DIR_PAGE_ENTRY_32 *dp0 = (struct DIR_PAGE_ENTRY_32 *)dp; -// NOTE: Danger. Check for of boundary. +u32 lcns =le32_to_cpu (dp->lcns_follow); + +if (lcns > t32) { + log->set_dirty = true; + goto out; + } +memmove (&dp->vcn, &dp0->vcn_low, -2 *sizeof (u64) + -le32_to_cpu (dp->lcns_follow) *sizeof (u64)); +2 *sizeof (u64) + lcns *sizeof (u64)); } end_conv_1:
Greg Kroah-Hartman
maintainerPATCH 791/1067 fs/ntfs3: add depth limit to indx_find_buffer to prevent stack overflow
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 1ebd684b8f627f75bc3e03f8b2ad8400fd1f02cd upstream.
indx_find_buffer() recursively descends the B+ tree index with no depth limit. A crafted NTFS image with circular index node references causes unbounded recursion, overflowing the kernel stack and panicking the system.
This is reachable by mounting a malicious NTFS filesystem (e.g. from a USB drive via desktop automount) and deleting a file whose index entry triggers the rebalancing fallback path in indx_delete_entry().
Add a depth parameter and bail out with -EINVAL when it reaches the fnd->nodes array bound, matching the constraint already enforced by fnd_push() in indx_find().
The related function indx_find() was previously patched for a similar infinite-loop issue (commit 1732053c8a6b), but indx_find_buffer() was missed.
--- fs/ntfs3/index.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-)
fs/ntfs3/index.c +12 -3
@@ -1991,13 +1991,21 @@ out1:static struct indx_node *indx_find_buffer (struct ntfs_index *indx,struct ntfs_inode *ni,const struct INDEX_ROOT *root, -__le64 vbn,struct indx_node *n) +__le64 vbn,struct indx_node *n, +int depth) {int err;const struct NTFS_DE *e;struct indx_node *r;const struct INDEX_HDR *hdr = n ? &n->index->ihdr : &root->ihdr; +/* +* Limit recursion depth to prevent stack overflow from crafted +* images. Use the same bound as the fnd->nodes array (20). +*/ +if (depth >ARRAY_SIZE (((struct ntfs_fnd *)NULL )->nodes)) +return ERR_PTR (-EINVAL ); +/* Step 1: Scan one level. */ for (e =hdr_first_de (hdr);; e =hdr_next_de (hdr, e)) {if (!e)
@@ -2018,7 +2026,8 @@ static struct indx_node *indx_find_buffeif (err)return ERR_PTR (err); - r =indx_find_buffer (indx, ni, root, vbn, n); + r =indx_find_buffer (indx, ni, root, vbn, n, + depth +1 );if (r)return r; }
@@ -2419,7 +2428,7 @@ int indx_delete_entry(struct ntfs_indexfnd_clear (fnd); - in =indx_find_buffer (indx, ni, root, sub_vbn,NULL ); + in =indx_find_buffer (indx, ni, root, sub_vbn,NULL ,0 );if (IS_ERR (in)) { err =PTR_ERR (in); goto out;
Greg Kroah-Hartman
maintainerPATCH 792/1067 fs/ntfs3: bound NTFS_DE view.data_off in UpdateRecordData{Root,Allocation}
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 3e127829e57f5190f612412ece4541cb96d5ec7a upstream.
In do_action()'s UpdateRecordDataRoot (fslog.c:3489) and UpdateRecordDataAllocation (fslog.c:3697) cases, the memmove destination is Add2Ptr(e, le16_to_cpu(e->view.data_off)), where e->view.data_off comes from an on-disk NTFS_DE inside an INDEX_ROOT or INDEX_BUFFER. Neither case validates view.data_off + dlen against e->size; the existing check_if_index_root / check_if_alloc_index helpers walk the entry chain and validate the entry's offset, but not its internal view fields.
The neighbouring read sites (e.g., fs/ntfs3/index.c when iterating view entries) check view.data_off + view.data_size <= e->size. Apply the same bound at the two memmove sites.
Reproduced under UML+KASAN on mainline 8d90b09e6741 via pr_warn-only probe instrumentation: with view.data_off forced to 0xFFFC, the memmove writes 32 bytes past the end of the NTFS_DE.
This is similar in shape to Pavitra Jha's 2026-05-02 patch "fs/ntfs3: prevent oob in case UpdateRecordDataRoot" (<[email protected]>) which proposes calling ntfs3_bad_de_range(); that helper does not exist in mainline. This patch uses inline checks.
--- fs/ntfs3/fslog.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+)
fs/ntfs3/fslog.c +18 -0
@@ -3515,6 +3515,18 @@ move_data: e =Add2Ptr (attr,le16_to_cpu (lrh->attr_off)); +/* +* e->view.data_off and dlen come from the on-disk +* INDEX_ROOT entry / LRH. The neighbouring read sites +* (e.g. fs/ntfs3/index.c) check that +* view.data_off + view.data_size <= e->size; mirror that +* bound here so the memmove cannot reach past the entry. +*/ +if (le16_to_cpu (e->view.data_off) >le16_to_cpu (e->size) || +le16_to_cpu (e->view.data_off) + dlen > +le16_to_cpu (e->size)) + goto dirty_vol; +memmove (Add2Ptr (e,le16_to_cpu (e->view.data_off)), data, dlen); mi->dirty = true;
@@ -3723,6 +3735,12 @@ move_data: goto dirty_vol; } +/* See UpdateRecordDataRoot for the rationale. */ +if (le16_to_cpu (e->view.data_off) >le16_to_cpu (e->size) || +le16_to_cpu (e->view.data_off) + dlen > +le16_to_cpu (e->size)) + goto dirty_vol; +memmove (Add2Ptr (e,le16_to_cpu (e->view.data_off)), data, dlen); a_dirty = true;
Greg Kroah-Hartman
maintainerPATCH 793/1067 ntfs3: cap RESTART_TABLE free-chain walker at rt->used
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 9611f644302c07d21bc8af97e3e06a3d30064253 upstream.
A crafted NTFS3 disk image triggers an in-kernel infinite loop at mount time, hanging the mounting thread and firing the soft-lockup watchdog within ~22s on multi-CPU hosts (panic with kernel.softlockup_panic=1). The bug is reachable from desktop USB auto-mount on distributions where udisks2 routes the NTFS signature to the in-tree ntfs3 driver (Arch family and an increasing fraction of Fedora / openSUSE / RHEL deployments); CAP_SYS_ADMIN-class manual mount elsewhere.
check_rstbl()'s second walker iterates the free-entry singly-linked list headed by rt->first_free with no upper bound on iteration count:
for (off = ff; off;) {
if (off == RESTART_ENTRY_ALLOCATED)
return false;
off = le32_to_cpu(*(__le32 *)Add2Ptr(rt, off));
if (off > ts - sizeof(__le32))
return false;
}The existing guards cover three exits: end-of-list (off == 0), the in-use marker (off == RESTART_ENTRY_ALLOCATED), and out-of-bounds (off > ts - sizeof(__le32)). None of the three prevents an in-bounds cycle.
A crafted on-disk RESTART_TABLE whose free chain contains a self-loop or A->B->A cycle whose offsets satisfy:
- in range [sizeof(struct RESTART_TABLE), ts - sizeof(__le32)]
- (off - sizeof(struct RESTART_TABLE)) % rsize == 0
passes all existing guards and spins the mount-time thread forever. Reproduced in UML by hand-forging a 2 MB NTFS3 image whose journal RESTART_TABLE first_free = 0x18 and whose entry at offset 0x18 stores 0x18 as its next pointer; mount of the forged image with the in-tree ntfs3 driver never returns.
Bound the walker by rt->used. Each entry on a legitimate free chain is unique, and the total slot count is ne = le16_to_cpu (rt->used). A traversal that visits more than ne slots is by construction malformed; reject it as a corrupt RESTART_TABLE.
After this patch, mount of the forged image returns with -EINVAL and a log_replay failure message, and mkntfs-produced legitimate images mount cleanly (verified in the same UML harness).
--- fs/ntfs3/fslog.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-)
fs/ntfs3/fslog.c +12 -1
@@ -764,8 +764,19 @@ static bool check_rstbl(const struct RES/* * Walk through the list headed by the first entry to make * sure none of the entries are currently being used. +* +* Bound traversal by ne (rt->used) to defeat a crafted on-disk +* cycle in the free chain. Each entry in a legitimate free +* list is unique, so a chain that visits more than ne slots +* is malformed. Without this guard, an attacker-controlled +* RESTART_TABLE with a self-loop or A->B->A cycle whose +* offsets satisfy the existing alignment + in-bounds guards +* spins forever at mount time. */ -for (off = ff; off;) { +for (off = ff, i =0 ; off; i++) { +if (i > ne) +return false; +if (off ==RESTART_ENTRY_ALLOCATED )return false;
Greg Kroah-Hartman
maintainerPATCH 794/1067 ntfs3: bound to_move in indx_insert_into_root before hdr_insert_head
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 9b6926ac9c970ae0b2c2fe6289b16e9aa10b6a67 upstream.
indx_insert_into_root() promotes a full resident $INDEX_ROOT into $INDEX_ALLOCATION and copies all non-last resident root entries into a newly allocated INDEX_BUFFER via hdr_insert_head(). The source byte count 'to_move' is summed from the on-disk resident entry sizes and is independent of the destination buffer size, which comes from root->index_block_size (via indx->index_bits).
A crafted NTFS image that keeps a valid, full resident root but shrinks root->index_block_size down to 512 after the root has been populated makes hdr_insert_head() memcpy attacker-controlled resident entry bytes past the end of the kmalloc(1u << indx->index_bits) allocation returned by indx_new(). For a 512-byte destination and a resident root whose non-last entries total 560 bytes, the memcpy overruns by 120 bytes and a following memmove extends the highest written offset to 136 bytes past the allocation. The overflow bytes are a direct copy of on-disk entries (via kmemdup), so they are fully attacker-controlled.
The write is reachable from unprivileged open(O_CREAT) on a mounted crafted NTFS image: a single sufficiently long create in a directory whose resident root is already full forces root promotion and triggers the copy.
This is a controlled out-of-bounds write of 120-136 bytes past a kmalloc(index_block_size) allocation, with attacker-controlled content. It is a bounded adjacent-heap corruption primitive; it is not an arbitrary-address write. Successful exploitation into a named victim object depends on the surrounding slab layout.
Reject the copy at the sink. The destination's INDEX_HDR already reports hdr_total (the payload capacity of the new buffer) and hdr_used (the bytes already consumed by the terminal END entry installed by indx_new()); require that to_move fits in the remaining payload before calling hdr_insert_head(). On mismatch, fail with -EINVAL and mark the filesystem as having a detected on-disk inconsistency, which is the same behaviour as the surrounding validation in this function.
--- fs/ntfs3/index.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+)
fs/ntfs3/index.c +16 -0
@@ -1730,6 +1730,22 @@ static int indx_insert_into_root(struct hdr_used =le32_to_cpu (hdr->used); hdr_total =le32_to_cpu (hdr->total); +/* +* The destination INDEX_BUFFER has 'hdr_total' bytes of payload +* available after the header, of which 'hdr_used' are already +* consumed by the single terminal END entry installed by +* indx_new(). A crafted image can present a resident root whose +* non-last entries (summing to 'to_move') exceed what fits in +* this buffer; copying them unchecked would overrun the +* kmalloc(1u << indx->index_bits) allocation backing the new +* buffer. Reject the copy in that case. +*/ +if (to_move > hdr_total - hdr_used) { + err = -EINVAL ; +ntfs_set_state (sbi,NTFS_DIRTY_ERROR ); + goto out_put_n; + } +/* Copy root entries into new buffer. */ hdr_insert_head (hdr, re, to_move);
Greg Kroah-Hartman
maintainerPATCH 795/1067 ntfs3: fix out-of-bounds read in decompress_lznt
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 7160a57192fb16d7a6fa9b7f5c7ac341d2444a89 upstream.
decompress_lznt() does not validate array index bounds before accessing the decompression table. A corrupted NTFS3 image with invalid compressed data can trigger an out-of-bounds read.
Add index bounds checking to prevent the OOB access.
--- fs/ntfs3/lznt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ntfs3/lznt.c +1 -1
@@ -240,7 +240,7 @@ static inline ssize_t decompress_chunk(uif (up - unc >LZNT_CHUNK_SIZE )return -EINVAL ;/* Correct index */ -while (unc + s_max_off[index] < up) +while (index <ARRAY_SIZE (s_max_off) -1 && unc + s_max_off[index] < up) index +=1 ;/* Check the current flag for zero. */
Greg Kroah-Hartman
maintainerPATCH 796/1067 power: supply: charger-manager: fix refcount leak in is_full_charged()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: WenTao Liang <[email protected]>
commit 4373cfa38ead58f980362c841b0d0bdf8c4d956c upstream.
In is_full_charged(), power_supply_get_by_name() is called to obtain a reference to the fuel_gauge power supply. If the voltage check (uV >= desc->fullbatt_uV) succeeds, the function returns true directly without releasing the reference, leaking the refcount.
Fix this by setting a flag and jumping to the out label where power_supply_put() properly drops the reference.
--- drivers/power/supply/charger-manager.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/power/supply/charger-manager.c +4 -2
@@ -302,8 +302,10 @@ static bool is_full_charged(struct chargif (cm->battery_status ==POWER_SUPPLY_STATUS_FULL && desc->fullbatt_vchkdrop_uV) uV += desc->fullbatt_vchkdrop_uV; -if (uV >= desc->fullbatt_uV) -return true; +if (uV >= desc->fullbatt_uV) { + is_full = true; + goto out; + } } }
Greg Kroah-Hartman
maintainerPATCH 797/1067 mips: sched: Fix CPUMASK_OFFSTACK memory corruption
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aaron Tomlin <[email protected]>
commit 98e37db4a34d3af3fb2f4648295c25b5e40b20e3 upstream.
This patch addresses a critical memory management flaw. When CONFIG_CPUMASK_OFFSTACK is enabled, cpumask_var_t is a pointer. Consequently, sizeof(new_mask) evaluates to the pointer size, causing copy_from_user() to clobber the mask pointer. Furthermore, the old logic performed copy_from_user() before allocating the mask.
Fix this by allocating new_mask first. To handle variable-sized user masks correctly, use cpumask_size() to truncate overly large user masks or pad undersized masks with zeros before copying the data directly into the allocated buffer.
--- arch/mips/kernel/mips-mt-fpaff.c | 28 +++++++++++++++------------- 1 file changed, 15 insertions(+), 13 deletions(-)
arch/mips/kernel/mips-mt-fpaff.c +15 -13
@@ -70,11 +70,16 @@ asmlinkage long mipsmt_sys_sched_setaffistruct task_struct *p;int retval; -if (len <sizeof (new_mask)) -return -EINVAL ; - -if (copy_from_user (&new_mask, user_mask_ptr,sizeof (new_mask))) -return -EFAULT ; +if (!alloc_cpumask_var (&new_mask,GFP_KERNEL )) +return -ENOMEM ; +if (len <cpumask_size ()) +cpumask_clear (new_mask); +else if (len >cpumask_size ()) + len =cpumask_size (); +if (copy_from_user (new_mask, user_mask_ptr, len)) { + retval = -EFAULT ; + goto out_free_new_mask; + }cpus_read_lock ();rcu_read_lock ();
@@ -83,7 +88,8 @@ asmlinkage long mipsmt_sys_sched_setaffiif (!p) {rcu_read_unlock ();cpus_read_unlock (); -return -ESRCH ; + retval = -ESRCH ; + goto out_free_new_mask; }/* Prevent p going away */
@@ -94,13 +100,9 @@ asmlinkage long mipsmt_sys_sched_setaffi retval = -ENOMEM ; goto out_put_task; } -if (!alloc_cpumask_var (&new_mask,GFP_KERNEL )) { - retval = -ENOMEM ; - goto out_free_cpus_allowed; - }if (!alloc_cpumask_var (&effective_mask,GFP_KERNEL )) { retval = -ENOMEM ; - goto out_free_new_mask; + goto out_free_cpus_allowed; }if (!check_same_owner (p) && !capable (CAP_SYS_NICE )) { retval = -EPERM ;
@@ -141,13 +143,13 @@ asmlinkage long mipsmt_sys_sched_setaffi } out_unlock:free_cpumask_var (effective_mask); -out_free_new_mask: -free_cpumask_var (new_mask); out_free_cpus_allowed:free_cpumask_var (cpus_allowed); out_put_task:put_task_struct (p);cpus_read_unlock (); +out_free_new_mask: +free_cpumask_var (new_mask);return retval; }
Greg Kroah-Hartman
maintainerPATCH 798/1067 riscv: cacheinfo: Fix node reference leak in populate_cache_leaves
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zishun Yi <[email protected]>
commit bf4a195f063b0a0805c1417f6aad1dd32ea48f0f upstream.
Currently, the while loop drops the reference to prev in each iteration. If the loop terminates early due to a break, the final of_node_put(np) correctly drops the reference to the current node.
However, if the loop terminates naturally because np == NULL, calling of_node_put(np) is a no-op. This leaves the last valid node stored in prev without its reference dropped, resulting in a node reference leak.
Fix this by changing the final of_node_put(np) to of_node_put(prev).
--- arch/riscv/kernel/cacheinfo.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
arch/riscv/kernel/cacheinfo.c +1 -1
@@ -141,7 +141,7 @@ int populate_cache_leaves(unsigned int c levels = level; } -of_node_put (np); +of_node_put (prev);return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 799/1067 proc: only bump parent nlink when registering directories
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
commit 16b02eb4b9b272c221255c20d34ccd5db53a3ed3 upstream.
proc_register() increments the parent directory's link count for every entry it registers, while remove_proc_entry() and remove_proc_subtree() decrement it only when the removed entry is a directory. Regular files thus inflate the parent's count while they exist, and leak one link permanently on every create and remove cycle.
For example, /proc/bus/pci/00 with twenty-two device files and no subdirectories reports nlink 24 instead of 2, and SR-IOV VF enable and disable cycles, each creating and removing the VF config space entries under /proc/bus/pci/<bus>, inflate the link count of that directory without bound.
Before commit e06689bf5701 ("proc: change ->nlink under proc_subdir_lock"), the increment lived in proc_mkdir_data() and proc_create_mount_point(), and was therefore applied only to directories. Moving it into proc_register() to bring it under proc_subdir_lock dropped the S_ISDIR check.
Thus, move the nlink accounting into pde_subdir_insert() and pde_erase(), only updating it for directories in both, so the link count is always changed together with the directory entry itself.
--- fs/proc/generic.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-)
fs/proc/generic.c +4 -5
@@ -112,6 +112,8 @@ static bool pde_subdir_insert(struct pro/* Add new node and rebalance tree. */ rb_link_node (&de->subdir_node, parent, new);rb_insert_color (&de->subdir_node, root); +if (S_ISDIR (de->mode)) + dir->nlink++;return true; }
@@ -400,7 +402,6 @@ struct proc_dir_entry *proc_register(strwrite_unlock (&proc_subdir_lock); goto out_free_inum; } - dir->nlink++;write_unlock (&proc_subdir_lock);return dp;
@@ -699,6 +700,8 @@ static void pde_erase(struct proc_dir_en {rb_erase (&pde->subdir_node, &parent->subdir);RB_CLEAR_NODE (&pde->subdir_node); +if (S_ISDIR (pde->mode)) + parent->nlink--; }/*
@@ -724,8 +727,6 @@ void remove_proc_entry(const char *name, de =NULL ; }else {pde_erase (de, parent); -if (S_ISDIR (de->mode)) - parent->nlink--; } }write_unlock (&proc_subdir_lock);
@@ -784,8 +785,6 @@ int remove_proc_subtree(const char *namecontinue ; } next = de->parent; -if (S_ISDIR (de->mode)) - next->nlink--;write_unlock (&proc_subdir_lock);proc_entry_rundown (de);
Greg Kroah-Hartman
maintainerPATCH 800/1067 mtd: slram: remove failed entries from the device list
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
commit 36f1648644d769c496a8e47e53603e863e358d73 upstream.
register_device() links a new slram_mtdlist entry before allocating all of the state needed by the entry. If a later allocation, memremap(), or mtd_device_register() fails, the partially initialized entry remains on the global list. A later cleanup can then dereference or free invalid state from that failed entry.
Unwind the partially initialized entry and clear the list tail on each failure path after the entry has been linked.
--- drivers/mtd/devices/slram.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-)
drivers/mtd/devices/slram.c +16 -6
@@ -129,6 +129,7 @@ static int slram_write(struct mtd_info *static int register_device (char *name,unsigned long start,unsigned long length) {slram_mtd_list_t **curmtd; +int ret = -ENOMEM ; curmtd = &slram_mtdlist;while (*curmtd) {
@@ -155,14 +156,15 @@ static int register_device(char *name, uif (!(*curmtd)->mtdinfo) {E ("slram: Cannot allocate new MTD device.\n" ); -return (-ENOMEM ); + goto err_free_list; }if (!(((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start =memremap (start, length,MEMREMAP_WB |MEMREMAP_WT |MEMREMAP_WC ))) {E ("slram: memremap failed\n" ); -return -EIO ; + ret = -EIO ; + goto err_free_priv; } ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end = ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start + length;
@@ -183,10 +185,8 @@ static int register_device(char *name, uif (mtd_device_register ((*curmtd)->mtdinfo,NULL ,0 )) {E ("slram: Failed to register new device\n" ); -memunmap (((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start); -kfree ((*curmtd)->mtdinfo->priv); -kfree ((*curmtd)->mtdinfo); -return (-EAGAIN ); + ret = -EAGAIN ; + goto err_unmap; }T ("slram: Registered device %s from %luKiB to %luKiB\n" , name, (start /1024 ), ((start + length) /1024 ));
@@ -194,6 +194,16 @@ static int register_device(char *name, u ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start, ((slram_priv_t *)(*curmtd)->mtdinfo->priv)->end);return (0 ); + +err_unmap: +memunmap (((slram_priv_t *)(*curmtd)->mtdinfo->priv)->start); +err_free_priv: +kfree ((*curmtd)->mtdinfo->priv); +err_free_list: +kfree ((*curmtd)->mtdinfo); +kfree (*curmtd); + *curmtd =NULL ; +return ret; }static void unregister_devices (void )
Greg Kroah-Hartman
maintainerPATCH 801/1067 scsi: smartpqi: Use shost_to_hba() in pqi_scan_finished()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Martin Wilck <[email protected]>
commit 57db1307afb1f83d45f5ff53b93f8d040100d13e upstream.
shost_to_hba() is used everywhere except to obtain pqi_ctrl_info from shosti, except in pqi_scan_finished(), where shost_priv() is used. This causes one pointer dereference to be missed, as shost->hostdata is a pointer in smartpqi. Fix it.
--- drivers/scsi/smartpqi/smartpqi_init.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/scsi/smartpqi/smartpqi_init.c +1 -1
@@ -2632,7 +2632,7 @@ static int pqi_scan_finished(struct Scsi {struct pqi_ctrl_info *ctrl_info; - ctrl_info =shost_priv (shost); + ctrl_info =shost_to_hba (shost);return !mutex_is_locked (&ctrl_info->scan_mutex); }
Greg Kroah-Hartman
maintainerPATCH 802/1067 scsi: sas: Skip opt_sectors when DMA reports no real optimization hint
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ionut Nechita <[email protected]>
commit be8fcd4a8217a916344c88a4b1b84f5736dda17e upstream.
sas_host_setup() unconditionally sets shost->opt_sectors from dma_opt_mapping_size().
When the IOMMU is disabled or in passthrough mode and no DMA ops provide an opt_mapping_size callback, dma_opt_mapping_size() returns min(dma_max_mapping_size(), SIZE_MAX) which equals dma_max_mapping_size() — a hard upper bound, not an optimization hint.
On a Dell PowerEdge R750 with mpt3sas (Broadcom SAS3816, FW 33.15.00.00) and intel_iommu=off the following values are observed:
dma_opt_mapping_size() = dma_max_mapping_size() (no real hint)
shost->max_sectors = 32767
opt_sectors = min(32767, huge >> 9) = 32767
optimal_io_size = 32767 << 9 = 16776704
→ round_down(16776704, 4096) = 16773120The SAS disk (SAMSUNG MZILT800HBHQ0D3) does not report an Optimal Transfer Length in VPD page B0, so sdkp->opt_xfer_blocks remains 0.
sd_revalidate_disk() then uses min_not_zero(0, opt_sectors) = opt_sectors, propagating the bogus value into the block device's optimal_io_size (visible as OPT-IO = 16773120 in lsblk --topology).
mkfs.xfs picks up optimal_io_size and minimum_io_size and computes:
swidth = 16773120 / 4096 = 4095
sunit = 8192 / 4096 = 2
Since 4095 % 2 != 0, XFS rejects the geometry:
SB stripe unit sanity check failed
This makes it impossible to create XFS filesystems (e.g. for /var/lib/docker) during system bootstrap.
Fix this by introducing a sas_dma_setup_opt_sectors() helper that sets opt_sectors only when dma_opt_mapping_size() is strictly less than dma_max_mapping_size(), indicating a genuine DMA optimization constraint.
The helper computes min(opt_sectors, max_sectors) first, then rounds down to a power of two so that filesystem geometry calculations always produce clean results.
When the two DMA values are equal, no backend provided a real hint, so opt_sectors stays at 0 ("no preference").
[mkp: implemented hch's suggestion]
--- drivers/scsi/scsi_transport_sas.c | 41 +++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 5 deletions(-)
drivers/scsi/scsi_transport_sas.c +36 -5
@@ -27,6 +27,7 @@#include <linux/module.h> #include <linux/jiffies.h> #include <linux/err.h> +#include <linux/log2.h> #include <linux/slab.h> #include <linux/string.h> #include <linux/blkdev.h>
@@ -220,12 +221,45 @@ static int sas_bsg_initialize(struct Scsi_Host *shost, struct sas_rphy *rphy)* SAS host attributes */ +/* +* Set shost->opt_sectors from the DMA optimal mapping size, but only +* when dma_opt_mapping_size() is strictly less than dma_max_mapping_size(), +* indicating a genuine optimization hint from an IOMMU or DMA backend. +* When the two are equal (e.g. IOMMU disabled / passthrough), no real +* hint exists, so leave opt_sectors at 0 to avoid bogus optimal_io_size +* values that break filesystem geometry (e.g. mkfs.xfs stripe alignment). +*/ +static void sas_dma_setup_opt_sectors (struct Scsi_Host *shost) +{ +struct device *dma_dev = shost->dma_dev; +size_t opt =dma_opt_mapping_size (dma_dev); +size_t max =dma_max_mapping_size (dma_dev); +unsigned int opt_sectors; + +/* opt >= max means no real hint was provided by the DMA layer */ +if (opt >= max) +return ; + +/* Clamp to max_sectors to avoid overflow in sector arithmetic */ + opt_sectors = min_t(unsigned int, opt >> SECTOR_SHIFT, + shost->max_sectors); + +/* Guard against zero before rounddown_pow_of_two() */ +if (!opt_sectors) +return ; + +/* +* Round down to power-of-two so filesystem geometry calculations +* (e.g. XFS stripe width/unit) always produce clean divisors. +*/ + shost->opt_sectors =rounddown_pow_of_two (opt_sectors); +} +static int sas_host_setup (struct transport_container *tc,struct device *dev,struct device *cdev) {struct Scsi_Host *shost =dev_to_shost (dev);struct sas_host_attrs *sas_host =to_sas_host_attrs (shost); -struct device *dma_dev = shost->dma_dev;INIT_LIST_HEAD (&sas_host->rphy_list);mutex_init (&sas_host->lock);
@@ -237,10 +271,7 @@ static int sas_host_setup(struct transport_container *tc, struct device *dev,dev_printk (KERN_ERR , dev,"fail to a bsg device %d\n" , shost->host_no); -if (dma_dev->dma_mask) { - shost->opt_sectors = min_t(unsigned int, shost->max_sectors, -dma_opt_mapping_size (dma_dev) >>SECTOR_SHIFT ); - } +sas_dma_setup_opt_sectors (shost);return 0 ; }
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 803/1067 ocfs2: use kzalloc for quota recovery bitmap allocation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
commit 93c8c6ea90be9e9df8fe14048ad4e3caad0770a6 upstream.
ocfs2 quota recovery allocates a bitmap buffer with kmalloc and does not fully initialize it. This can lead to use of uninitialized bits during quota recovery from a corrupted filesystem image.
Use kzalloc instead to ensure the bitmap is zero-initialized.
--- fs/ocfs2/quota_local.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/ocfs2/quota_local.c +1 -1
@@ -302,7 +302,7 @@ static int ocfs2_add_recovery_chunk(struif (!rc)return -ENOMEM ; rc->rc_chunk = chunk; - rc->rc_bitmap =kmalloc (sb->s_blocksize,GFP_NOFS ); + rc->rc_bitmap =kzalloc (sb->s_blocksize,GFP_NOFS );if (!rc->rc_bitmap) {kfree (rc);return -ENOMEM ;
Greg Kroah-Hartman
maintainerPATCH 804/1067 mtd: rawnand: pl353: fix probe resource allocation
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bastien Curutchet <[email protected]>
commit 19ed11aee966d91beebdef9d32ce926474872f79 upstream.
During probe(), the devm_ioremap() is called with the parent device instead of the current one. So when the module is unloaded, the register area isn't released.
Target the pl35x device in the devm_ioremap() instead of its parent.
--- drivers/mtd/nand/raw/pl35x-nand-controller.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/nand/raw/pl35x-nand-controller.c +1 -1
@@ -1155,7 +1155,7 @@ static int pl35x_nand_probe(struct platf nfc->controller.ops = &pl35x_nandc_ops;INIT_LIST_HEAD (&nfc->chips); - nfc->conf_regs =devm_ioremap_resource (&smc_amba->dev, &smc_amba->res); + nfc->conf_regs =devm_ioremap_resource (nfc->dev, &smc_amba->res);if (IS_ERR (nfc->conf_regs))return PTR_ERR (nfc->conf_regs);
Greg Kroah-Hartman
maintainerPATCH 805/1067 net/9p: fix infinite loop in p9_client_rpc on fatal signal
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Vasiliy Kovalev <[email protected]>
commit 6b4f48728faa8bb514368f7eacda05565dea8696 upstream.
When p9_client_rpc() is called with type P9_TFLUSH and the transport has no peer (e.g. fd transport backed by pipes with no 9p server), a fatal signal causes an infinite loop:
again:
err = io_wait_event_killable(req->wq, ...)
/* SIGKILL wakes the task, returns -ERESTARTSYS */
if (err == -ERESTARTSYS && c->status == Connected &&
type == P9_TFLUSH) {
sigpending = 1;
clear_thread_flag(TIF_SIGPENDING);
goto again;
}clear_thread_flag() clears TIF_SIGPENDING before jumping back to io_wait_event_killable(). signal_pending_state() checks TIF_SIGPENDING, finds it zero, and the task goes to sleep again. The task can only wake on the next signal delivery that calls signal_wake_up() and sets TIF_SIGPENDING again. When that happens the loop repeats, clears TIF_SIGPENDING, and sleeps again indefinitely.
This is triggered in practice by coredump_wait(): when a thread in a multi-threaded process causes a coredump (e.g. via SIGSYS from Syscall User Dispatch), coredump_wait() sends SIGKILL to all other threads and waits for them to call mm_release(). If one of those threads is blocked in p9_client_rpc() over an fd transport with no peer, it enters the P9_TFLUSH loop and never calls mm_release(), so coredump_wait() stalls forever:
INFO: task syz.0.18:676 blocked for more than 143 seconds.
Not tainted 6.12.77+ #1
task:syz.0.18 state:D stack:27600 pid:676 tgid:673 ppid:630 flags:0x00000004
Call Trace:
<TASK>
context_switch kernel/sched/core.c:5344 [inline]
__schedule+0xcb4/0x5d50 kernel/sched/core.c:6724
__schedule_loop kernel/sched/core.c:6801 [inline]
schedule+0xe5/0x350 kernel/sched/core.c:6816
schedule_timeout+0x253/0x290 kernel/time/timer.c:2593
do_wait_for_common kernel/sched/completion.c:95 [inline]
__wait_for_common+0x409/0x600 kernel/sched/completion.c:116
wait_for_common kernel/sched/completion.c:127 [inline]
wait_for_completion_state+0x1d/0x40 kernel/sched/completion.c:264
coredump_wait fs/coredump.c:448 [inline]
do_coredump+0x854/0x4350 fs/coredump.c:629
get_signal+0x1425/0x2730 kernel/signal.c:2903
arch_do_signal_or_restart+0x81/0x880 arch/x86/kernel/signal.c:337
exit_to_user_mode_loop kernel/entry/common.c:111 [inline]
exit_to_user_mode_prepare include/linux/entry-common.h:328 [inline]
__syscall_exit_to_user_mode_work kernel/entry/common.c:207 [inline]
syscall_exit_to_user_mode+0xf9/0x160 kernel/entry/common.c:218
do_syscall_64+0x102/0x220 arch/x86/entry/common.c:84
entry_SYSCALL_64_after_hwframe+0x77/0x7f
</TASK>Fix: check fatal_signal_pending() before clearing TIF_SIGPENDING in the P9_TFLUSH retry loop. At that point TIF_SIGPENDING is still set, so fatal_signal_pending() works correctly. If a fatal signal is pending, jump to recalc_sigpending to restore TIF_SIGPENDING and return -ERESTARTSYS to the caller.
The same defect is present in stable kernels back to 5.4. On those kernels the infinite loop is broken earlier by a second SIGKILL from the parent process (e.g. kill_and_wait() retrying after a timeout), resulting in a zombie process and a shutdown delay rather than a permanent D-state hang, but the underlying flaw is the same.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
Message-ID: <[email protected]>
--- net/9p/client.c | 2 ++ 1 file changed, 2 insertions(+)
net/9p/client.c +2 -0
@@ -716,6 +716,8 @@ again:if (err == -ERESTARTSYS && c->status == Connected && type ==P9_TFLUSH ) { +if (fatal_signal_pending (current)) + goto recalc_sigpending; sigpending =1 ;clear_thread_flag (TIF_SIGPENDING ); goto again;
Greg Kroah-Hartman
maintainerPATCH 806/1067 mtd: rawnand: fix condition in nand_select_target()
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Arseniy Krasnov <[email protected]>
commit 8507c2cc9e4fa402401819f44d1e8a5ef4d11d8b upstream.
'cs' here must be in range [0:nanddev_ntargets[.
--- drivers/mtd/nand/raw/nand_base.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/mtd/nand/raw/nand_base.c +1 -1
@@ -175,7 +175,7 @@ void nand_select_target(struct nand_chip* cs should always lie between 0 and nanddev_ntargets(), when that's * not the case it's a bug and the caller should be fixed. */ -if (WARN_ON (cs >nanddev_ntargets (&chip->base))) +if (WARN_ON (cs >=nanddev_ntargets (&chip->base)))return ; chip->cur_cs = cs;
Greg Kroah-Hartman
maintainerPATCH 807/1067 ocfs2: avoid moving extents to occupied clusters
In reply to Greg Kroah-Hartman6.1-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kyle Zeng <[email protected]>
commit 22920541c35a9f23f219038ba5874c843a7c4419 upstream.
For non-auto OCFS2_IOC_MOVE_EXT operations, userspace supplies a physical me_goal. ocfs2_move_extent() initializes new_phys_cpos from that goal and expects ocfs2_probe_alloc_group() to replace it with a free run in the target block group.
The probe currently leaves *phys_cpos unchanged if the scan reaches the end of the group without finding a free run. An occupied goal at the last bit can therefore survive the probe and be passed to __ocfs2_move_extent(), which copies file data into a cluster still owned by another inode before the bitmap is updated.
When the probe does find a free run, it also subtracts move_len from the ending bit. The start of an N-bit run ending at i is i - N + 1, so the current calculation can report the bit immediately before the free run.
Clear *phys_cpos before scanning and use the correct free-run start. Callers already treat a zero result as -ENOSPC, so failed probes no longer continue with an occupied caller-controlled goal.
--- fs/ocfs2/move_extents.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/ocfs2/move_extents.c +3 -1
@@ -534,6 +534,8 @@ static void ocfs2_probe_alloc_group(struu32 base_cpos =ocfs2_blocks_to_clusters (inode->i_sb,le64_to_cpu (gd->bg_blkno)); + *phys_cpos =0 ; +for (i = base_bit; i <le16_to_cpu (gd->bg_bits); i++) { used =ocfs2_test_bit (i, (unsigned long *)gd->bg_bitmap);
@@ -555,7 +557,7 @@ static void ocfs2_probe_alloc_group(stru last_free_bits++;if (last_free_bits == move_len) { - i -= move_len; + i = i - move_len +1 ; *goal_bit = i; *phys_cpos = base_cpos + i;break ;