5.10.270-rc1 review
Subsystems (2)
Greg Kroah-Hartman
maintainerPATCH 122/798 openrisc: fix arbitrary kernel memory access via or1k_atomic syscall
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ali Ahmet Memis <[email protected]>
commit 78004e9a87f240df03e2f73120d291763c32e0a7 upstream.
sys_or1k_atomic() (syscall 244 in the "or1k" ABI) takes two user pointers, v1 and v2, and swaps the words they point to in hand-written assembly.
l.lwz r29,0(r4)
l.lwz r27,0(r5)
l.sw 0(r4),r27
l.sw 0(r5),r29The pointers are not checked with access_ok(). The four memory accesses also have no exception table entries.
A caller passes a kernel address as either pointer, and the syscall reads from and writes to it directly.
This gives an unprivileged process a kernel read/write primitive. It overwrites kernel data such as the sys_call_table, gaining code execution in kernel context.
Check both pointers before entering the critical section. Add fixups for the four memory accesses so faults on valid but unmapped user addresses return -EFAULT.
--- arch/openrisc/kernel/entry.S | 43 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 39 insertions(+), 4 deletions(-)
arch/openrisc/kernel/entry.S +39 -4
@@ -1205,15 +1205,50 @@ _no_syscall_trace: * */ +/* Keep this literal; hi()/lo() can't use the UL-suffixed TASK_SIZE. */ +#define OR1K_ATOMIC_ADDR_LIMIT 0x7ffffffc + ENTRY(sys_or1k_atomic) /* FIXME: This ignores r3 and always does an XCHG */ + + /* Check both user pointers before accessing them. */ + l.movhi r13,hi(OR1K_ATOMIC_ADDR_LIMIT) + l.ori r13,r13,lo(OR1K_ATOMIC_ADDR_LIMIT) + l.sfgtu r4,r13 + l.bf 9f + l.nop + l.sfgtu r5,r13 + l.bf 9f + l.nop + DISABLE_INTERRUPTS(r17,r19) - l.lwz r29,0(r4) - l.lwz r27,0(r5) - l.sw 0(r4),r27 - l.sw 0(r5),r29 +10: l.lwz r29,0(r4) +11: l.lwz r27,0(r5) +12: l.sw 0(r4),r27 +13: l.sw 0(r5),r29 ENABLE_INTERRUPTS(r17) l.jr r9 l.or r11,r0,r0 + /* + * Either pointer was outside user space, or turned out to be + * unmapped/inaccessible when we actually touched it. + */ +9: l.jr r9 + l.addi r11,r0,-EFAULT + + .section .fixup, "ax" +14: + ENABLE_INTERRUPTS(r17) + l.j 9b + l.nop + .previous + + .section __ex_table, "a" + .long 10b, 14b + .long 11b, 14b + .long 12b, 14b + .long 13b, 14b + .previous + /* ============================================================[ EOF ]=== */
Greg Kroah-Hartman
maintainerPATCH 123/798 openvswitch: only skb_tx_error() a packet we are about to drop
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
commit 0dbc2398fca3bb33eda963849f865ddb1b3aa05e upstream.
queue_userspace_packet() borrows the packet skb -- it only copies it into a private netlink message (user_skb) and does not own it; on return do_execute_actions() keeps forwarding it through the flow's remaining actions. Its error path nevertheless calls skb_tx_error(skb), which via skb_zcopy_clear() does skb_shinfo(skb)->flags &= ~SKBFL_ALL_ZEROCOPY, stripping SKBFL_SHARED_FRAG from that live skb (skb_tx_error()'s kerneldoc says "skb must be freed afterwards").
For a MSG_ZEROCOPY skb carrying page-cache frags, SKBFL_SHARED_FRAG is what makes esp_input() skb_cow_data() before in-place AEAD; once it is stripped a later local ESP-in-UDP delivery decrypts in place over pages the sender does not own -- an unprivileged page-cache write (the "Fragnesia" primitive).do_execute_actions() ignores output_userspace()'s return value, so any action after a failed USERSPACE upcall inherits the stripped skb.
Move the skb_tx_error() to the flow-miss drop path - the "default" branch of ovs_dp_process_packet()'s switch(error), before kfree_skb().
The call has been here since commit 36d5fe6a0007 ("core, nfqueue,
openvswitch: Orphan frags in skb_zerocopy and handle errors") but was harmless until esp_input() began relying on SKBFL_SHARED_FRAG to gate in-place decrypt; only then did stripping it on a still-forwarded skb become a page-cache write primitive.
--- net/openvswitch/datapath.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
net/openvswitch/datapath.c +1 -2
@@ -249,6 +249,7 @@ void ovs_dp_process_packet(struct sk_bufconsume_skb (skb);break ;default : +skb_tx_error (skb);kfree_skb (skb);break ; }
@@ -544,8 +545,6 @@ static int queue_userspace_packet(struct err =genlmsg_unicast (ovs_dp_get_net (dp), user_skb, upcall_info->portid); user_skb =NULL ; out: -if (err) -skb_tx_error (skb);consume_skb (user_skb);consume_skb (nskb);
Greg Kroah-Hartman
maintainerPATCH 124/798 hwmon: (max6621) fix negative temperature offset and crit readings
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit acc52bd431e2d8698fae8d82a74ac45d79b62e0a upstream.
max6621_read() reads the CONFIG2 offset and the critical alert threshold registers into a u32 and scales them without sign extension:
/* offset */ *val = (regval >> MAX6621_REG_TEMP_SHIFT) * 1000L; /* crit */ *val = regval * 1000L;
Both attributes are writable and their write paths clamp to a negative minimum and encode negative values, so a value written as negative is read back as a large positive number. For example, writing a -10 degrees C offset stores max6621_temp_mc2reg(-10000) = (-10 << 6) = 0xfd80; the read then computes 0xfd80 >> 6 = 1014 -> 1014000 instead of -10000.
Cast the register value to s16 before scaling so the read preserves the sign the write path encodes. The temperature input path already uses an s8 intermediate and is left unchanged.
--- drivers/hwmon/max6621.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/max6621.c +2 -2
@@ -239,7 +239,7 @@ max6621_read(struct device *dev, enum hwif (ret)return ret; - *val = (regval >>MAX6621_REG_TEMP_SHIFT ) * + *val = ((s16 )regval >>MAX6621_REG_TEMP_SHIFT ) *1000L ;break ;
@@ -254,7 +254,7 @@ max6621_read(struct device *dev, enum hwif (ret)return ret; - *val = regval *1000L ; + *val = (s16 )regval *1000L ;break ;case hwmon_temp_crit_alarm:
Greg Kroah-Hartman
maintainerPATCH 125/798 hwmon: (max6621) fix temperature clamp range
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit 24fbeb83d9b750a36da42cb835a154d80fd3d495 upstream.
MAX6621_TEMP_INPUT_MIN and MAX6621_TEMP_INPUT_MAX are used to clamp the writable offset and critical thresholds. They are defined as -127000 and 128000.
The driver decodes the temperature through an s8 and its own comment in max6621_read() documents an 8-bit two's complement value, whose range is -128 to +127 degrees C. The current limits therefore reject the valid -128 degrees C and accept +128 degrees C, which does not fit the 8-bit range.
Correct the limits to -128000 and 127000.
--- drivers/hwmon/max6621.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/hwmon/max6621.c +2 -2
@@ -17,8 +17,8 @@#define MAX6621_DRV_NAME "max6621"#define MAX6621_TEMP_INPUT_REG_NUM 9 -#define MAX6621_TEMP_INPUT_MIN -127000 -#define MAX6621_TEMP_INPUT_MAX 128000 +#define MAX6621_TEMP_INPUT_MIN -128000 +#define MAX6621_TEMP_INPUT_MAX 127000#define MAX6621_TEMP_ALERT_CHAN_SHIFT 1#define MAX6621_TEMP_S0D0_REG 0x00
Greg Kroah-Hartman
maintainerPATCH 126/798 lockd: pin next file across nlm_inspect_file lock-drop
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 526c49cff3f72c3ec74752016380c7567040581b upstream.
nlm_traverse_files() pins the current file with f_count++ across a mutex_unlock for nlm_inspect_file(), but nothing pins the saved next pointer. A concurrent nlm_release_file() can kfree the next file during the unlock window, and the iterator dereferences freed memory on the next loop step.
Pin both current and next before the lock-drop. Advance by swapping the pinned cursors at the end of each iteration so next is always held alive across the unlock.
Always call nlm_file_release() after dropping the iteration pin, regardless of whether the file matched the predicate. Use nlm_file_inuse(), which does a live walk of the inode lock list, rather than the cached f_locks field, so skipped files that never ran nlm_inspect_file() are evaluated correctly.
Because every file in a hash bucket is now pinned and released, files skipped by the is_failover_file predicate that have no locks, blocks, shares, or external references are deleted during traversal. The old code never evaluated skipped files for cleanup. The new behavior is intentional: such files are stale and should not persist in the table.
--- fs/lockd/svcsubs.c | 53 ++++++++++++++++++++++++++++++----------------------- 1 file changed, 30 insertions(+), 23 deletions(-)
fs/lockd/svcsubs.c +30 -23
@@ -286,12 +286,10 @@ nlm_file_inuse(struct nlm_file *file)return 0 ; } -static void nlm_close_files (struct nlm_file *file) +static void nlm_file_release (struct nlm_file *file) { -if (file->f_file[O_RDONLY ]) - nlmsvc_ops->fclose (file->f_file[O_RDONLY ]); -if (file->f_file[O_WRONLY ]) - nlmsvc_ops->fclose (file->f_file[O_WRONLY ]); +if (!nlm_file_inuse (file)) +nlm_delete_file (file); }/*
@@ -301,32 +299,41 @@ static int nlm_traverse_files(void *data, nlm_host_match_fn_t match, int (*is_failover_file)(void *data, struct nlm_file *file)) { -struct hlist_node *next; -struct nlm_file *file; +struct nlm_file *file, *next;int i, ret =0 ;mutex_lock (&nlm_file_mutex);for (i =0 ; i <FILE_NRHASH ; i++) { -hlist_for_each_entry_safe (file, next, &nlm_files[i], f_list) { -if (is_failover_file && !is_failover_file (data, file)) -continue ; + file =hlist_entry_safe (nlm_files[i].first, + struct nlm_file, f_list); +if (file) file->f_count++; -mutex_unlock (&nlm_file_mutex); +while (file) { +/* +* Pin the next neighbour before we drop the mutex +* for nlm_inspect_file(); a concurrent +* nlm_release_file() under the same mutex would +* otherwise be free to unlink and kfree it during +* the unlock window, leaving us to dereference a +* freed slab when we walked to next afterwards. +*/ + next =hlist_entry_safe (file->f_list.next, + struct nlm_file, f_list); +if (next) + next->f_count++; -/* Traverse locks, blocks and shares of this file -* and update file->f_locks count */ -if (nlm_inspect_file (data, file, match)) - ret =1 ; +if (!is_failover_file ||is_failover_file (data, file)) { +mutex_unlock (&nlm_file_mutex); -mutex_lock (&nlm_file_mutex); - file->f_count--; -/* No more references to this file. Let go of it. */ -if (list_empty (&file->f_blocks) && !file->f_locks - && !file->f_shares && !file->f_count) { -hlist_del (&file->f_list); -nlm_close_files (file); -kfree (file); +if (nlm_inspect_file (data, file, match)) + ret =1 ; + +mutex_lock (&nlm_file_mutex); } + + file->f_count--; +nlm_file_release (file); + file = next; } }mutex_unlock (&nlm_file_mutex);
Greg Kroah-Hartman
maintainerPATCH 127/798 nvme: nvme-fc: Fix nvme_fc_create_hw_io_queues() queue deletion in error path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ewan D. Milne <[email protected]>
commit 22eb631bf86ee3246f47885e4fa94154a46863e4 upstream.
nvme_fc_create_hw_io_queues() will call __nvme_fc_delete_hw_queue() for the last queue on which __nvme_fc_create_hw_queue() reported an error when deleting all the io queues if they cannot all be created. This is incorrect since the last queue did not actually get created.
The most recent change to this code was commit 17a1ec08ce70 ("nvme/fc: simplify error handling of nvme_fc_create_hw_io_queues") which moved the cleanup to thedelete_queues: label and changed the loop bounds, however the code was not correct prior to this change in a different way. The original commit e399441de911 ("nvme-fabrics: Add host support for FC transport") had a different error which called __nvme_fc_delete_hw_queue() on queue index 0 which is used for the admin queue.
Fix this by correcting the initial loop index when deleting the io queues.
--- drivers/nvme/host/fc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/host/fc.c +1 -1
@@ -2325,7 +2325,7 @@ nvme_fc_create_hw_io_queues(struct nvme_return 0 ; delete_queues: -for (; i >0 ; i--) +for (--i; i >0 ; i--)__nvme_fc_delete_hw_queue (ctrl, &ctrl->queues[i], i);return ret; }
Greg Kroah-Hartman
maintainerPATCH 128/798 nvme: zero the discard fallback page
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit bededeaaeff404978a5a8e2a605a6c3017cddd3e upstream.
nvme_setup_discard() always maps sizeof(struct nvme_dsm_range) * NVME_DSM_MAX_RANGES = 4096 bytes as the DSM payload however many ranges the command declares, because some devices ignore the 'Number of Ranges' field - the Fixes: commit records two that read past the declared ranges. A single-range discard fills only the first 16 bytes.
Normally the buffer comes from kzalloc() and the other 4080 bytes are zero. When that allocation fails the code falls back to the per-controller ctrl->discard_page, which nvme_init_ctrl() obtains with alloc_page(GFP_KERNEL) and nothing ever zeroes, so those 4080 bytes are whatever the page last held and are handed to the controller. Reaching it requires the kzalloc(GFP_ATOMIC | __GFP_NOWARN) to fail, that is memory pressure; it is not remotely triggerable. Failing the allocation under KMSAN reproduces it, with the leaked tail full of vmemmap struct page pointers. The extent in the report is a partial transfer of the payload, not the whole 4096 bytes; the 16-byte boundary in it is the one declared range:
[ 11.991601] BUG: KMSAN: uninit-value in dma_map_phys+0x14c8/0x1900 [ 11.991969] dma_map_phys+0x14c8/0x1900 [ 11.992220] dma_map_page_attrs+0xcf/0x130 [ 11.992485] e1000_xmit_frame+0x4099/0x6d10 [ 11.992768] dev_hard_start_xmit+0x22f/0xa80 [ 11.993068] sch_direct_xmit+0x35c/0xcb0 [ 11.993315] __dev_queue_xmit+0x1ee5/0x5eb0 [ 11.993608] ip_finish_output2+0x1903/0x1c30 [ 11.993881] ip_finish_output+0x288/0x870 [ 11.994125] ip_output+0x15e/0x400 [ 11.994365] __ip_queue_xmit+0x1e85/0x1fb0 [ 11.994639] ip_queue_xmit+0x60/0x80 [ 11.994899] __tcp_transmit_skb+0x4e71/0x5fa0 [ 11.995210] tcp_write_xmit+0x3a36/0x9160 [ 11.995533] __tcp_push_pending_frames+0xc5/0x3c0 [ 11.995854] tcp_push+0x7dc/0x840 [ 11.996076] tcp_sendmsg_locked+0x766c/0x8400 [ 11.996371] tcp_sendmsg+0x4b/0x90 [ 11.996572] inet_sendmsg+0x134/0x2a0 [ 11.996823] __sock_sendmsg+0x265/0x360 [ 11.997076] sock_sendmsg+0x100/0x1e0 [ 11.997293] nvme_tcp_try_send+0x196f/0x6370 [ 11.997605] nvme_tcp_queue_rq+0x1d54/0x20b0 [ 11.997882] blk_mq_dispatch_rq_list+0x5ee/0x2e50 [ 11.998175] __blk_mq_sched_dispatch_requests+0x16dc/0x24a0 [ 11.998539] blk_mq_sched_dispatch_requests+0x11b/0x2c0 [ 11.998865] blk_mq_run_work_fn+0x13b/0x280 [ 11.999146] process_scheduled_works+0x966/0x1ad0 [ 11.999465] worker_thread+0xe44/0x1480 [ 11.999709] kthread+0x53b/0x600 [ 11.999927] ret_from_fork+0x29f/0x7c0 [ 12.000191] ret_from_fork_asm+0x1a/0x30 [ 12.000460] [ 12.000558] Uninit was created at: [ 12.000788] __alloc_frozen_pages_noprof+0x8bf/0xd30 [ 12.001096] alloc_pages_mpol+0x1d0/0x5f0 [ 12.001326] alloc_pages_noprof+0x102/0x290 [ 12.001627] nvme_init_ctrl+0x5a3/0x9f0 [ 12.001891] nvme_tcp_create_ctrl+0xd75/0x19b0 [ 12.002170] nvmf_dev_write+0x4c68/0x4fd0 [ 12.002426] vfs_write+0x587/0x1a10 [ 12.002636] __x64_sys_write+0x207/0x4f0 [ 12.002874] x64_sys_call+0x2ff0/0x3ea0 [ 12.003123] do_syscall_64+0x147/0x3b0 [ 12.003400] entry_SYSCALL_64_after_hwframe+0x77/0x7f [ 12.003680] [ 12.003777] Bytes 16-2843 of 2844 are uninitialized [ 12.004068] Memory access of size 2844 starts at ffff888109f82000 [ 12.004412] [ 12.004530] CPU: 0 UID: 0 PID: 101 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMECTL-gf5098b6bae76 #1 PREEMPT(lazy) [ 12.005127] Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 [ 12.005762] Workqueue: kblockd blk_mq_run_work_fn [ 12.006073] =====================================================
Allocate the page with __GFP_ZERO. The single allocation site covers every use of it: bytes no discard has written stay zero, and bytes one did write hold that controller's own range list, which it has already been sent.
--- drivers/nvme/host/core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/nvme/host/core.c +1 -1
@@ -4630,7 +4630,7 @@ int nvme_init_ctrl(struct nvme_ctrl *ctrBUILD_BUG_ON (NVME_DSM_MAX_RANGES *sizeof (struct nvme_dsm_range ) >PAGE_SIZE ); - ctrl->discard_page =alloc_page (GFP_KERNEL ); + ctrl->discard_page =alloc_page (GFP_KERNEL | __GFP_ZERO);if (!ctrl->discard_page) { ret = -ENOMEM ; goto out;
Greg Kroah-Hartman
maintainerPATCH 129/798 nvme-tcp: do not accept C2HData based on blk_rq_payload_bytes() alone
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit 3a4aa9e6ad3e35f8e24d5eaf38ee4d437075fb36 upstream.
Commit 25e5cb780e62 ("nvme-tcp: fix possible crash in write_zeroes processing") established that blk_rq_payload_bytes() must not be read without first checking blk_rq_nr_phys_segments(), and recorded the result in nvme_tcp_setup_cmd_pdu() as req->data_len. The receive side was left as it was.
The two differ for REQ_OP_WRITE_ZEROES, which has no physical segments but a non-zero blk_rq_bytes(), so setup leaves req->iter untouched while the receive gate lets a C2HData through and nvme_tcp_recv_data() copies into whatever the previous command on that tag left there. The driver-private area is zeroed only when the tag set is allocated.
Reproduced with a test target that leaves a residual iterator on a tag and then sends a C2HData for a WRITE_ZEROES command on the same tag:
BUG: KASAN: wild-memory-access in _copy_to_iter+0x642/0x1330 Write of size 512 at addr ffe728c2175dfa81 by task kworker/0:1H/103 CPU: 0 UID: 0 PID: 103 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMETCP-gf5098b6bae76 #1 PREEMPT(lazy) Hardware name: QEMU Ubuntu 24.04 PC v2 (i440FX + PIIX, arch_caps fix, 1996), BIOS 1.16.3-debian-1.16.3-2 04/01/2014 Workqueue: nvme_tcp_wq nvme_tcp_io_work Call Trace: <TASK> dump_stack_lvl+0x53/0x70 kasan_report+0xce/0x100 ? _copy_to_iter+0x642/0x1330 kasan_check_range+0x105/0x1b0 __asan_memcpy+0x3c/0x60 _copy_to_iter+0x642/0x1330 ? __pfx_sock_has_perm+0x10/0x10 ? worker_thread+0x45b/0xd10 ? __pfx__copy_to_iter+0x10/0x10 ? _raw_spin_lock_bh+0x83/0xe0 ? __pfx__raw_spin_lock_bh+0x10/0x10 __skb_datagram_iter+0xf3/0x820 ? __pfx_simple_copy_to_iter+0x10/0x10 ? __asan_memcpy+0x3c/0x60 ? skb_copy_bits+0x58d/0x830 skb_copy_datagram_iter+0x37/0x120 nvme_tcp_recv_skb+0xa07/0x4320 ? __pfx_nvme_tcp_recv_skb+0x10/0x10 __tcp_read_sock+0x1ab/0x810 ? __pfx_nvme_tcp_recv_skb+0x10/0x10 ? __pfx_lock_sock_nested+0x10/0x10 ? __pfx___tcp_read_sock+0x10/0x10 nvme_tcp_try_recv+0x152/0x1e0 ? __pfx_nvme_tcp_try_recv+0x10/0x10 ? __pfx_mutex_unlock+0x10/0x10 nvme_tcp_io_work+0x1e4/0x6c0 ? __schedule+0x181a/0x49f0 ? __pfx_nvme_tcp_io_work+0x10/0x10 process_one_work+0x633/0x1030
Keep the blk_rq_payload_bytes() test and add req->data_len to it. The old test is what rejects a C2HData naming a tag that is no longer in flight, because blk_update_request() zeroes rq->__data_len on completion; req->data_len and req->curr_bio are driver-private and survive completion, so they cannot stand in for it. Setup initialises the iterator only when both req->curr_bio and req->data_len are set, so the gate now tests the same two.
--- drivers/nvme/host/tcp.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/nvme/host/tcp.c +3 -1
@@ -545,6 +545,7 @@ static int nvme_tcp_process_nvme_cqe(strstatic int nvme_tcp_handle_c2h_data (struct nvme_tcp_queue *queue,struct nvme_tcp_data_pdu *pdu) { +struct nvme_tcp_request *req;struct request *rq; rq =nvme_find_rq (nvme_tcp_tagset (queue), pdu->command_id);
@@ -555,7 +556,8 @@ static int nvme_tcp_handle_c2h_data(strureturn -ENOENT ; } -if (!blk_rq_payload_bytes (rq)) { + req =blk_mq_rq_to_pdu (rq); +if (!blk_rq_payload_bytes (rq) || !req->curr_bio || !req->data_len) {dev_err (queue->ctrl->ctrl.device,"queue %d tag %#x unexpected data\n" ,nvme_tcp_queue_id (queue), rq->tag);
Greg Kroah-Hartman
maintainerPATCH 130/798 sctp: stop processing a packet once its association is deleted
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
commit 47e15a8d12e366d0d261bcbc394394f44418938d upstream.
sctp_endpoint_bh_rcv() looks the association up only when chunk->asoc is NULL, and caches the result in chunk->asoc and chunk->transport without taking a reference.
A packet that matches no association is handed to the endpoint, so a peer can bundle COOKIE ECHO, SHUTDOWN and SHUTDOWN ACK in one packet. The COOKIE ECHO creates the association, the SHUTDOWN chunk caches it, and with the outqueue empty the SHUTDOWN ACK reaches sctp_sf_do_9_2_final(), so the association and its transports are freed.
The endpoint loop has no counterpart to the asoc->base.dead check in sctp_assoc_bh_rcv(). The next chunk writes to last_time_heard in the freed transport and is then passed to sctp_do_sm() with the freed association. The transport is freed through RCU, so this needs the packet to come off the socket backlog, where the loop runs in task context.
The endpoint loop cannot do the same check: it holds no reference on the association, so reading asoc->base.dead would itself be a use-after-free. Mark the packet for discard in the command interpreter, just before it deletes the association. That is also before sctp_inq_free() releases the chunk on the association receive path.
sctp_sf_do_5_2_4_dupcook() issues SCTP_CMD_DELETE_TCB for the temporary association, while the one the packet belongs to stays alive. A restarting peer can bundle DATA behind its COOKIE ECHO, so compare against chunk->asoc and leave that case alone.
--- net/sctp/sm_sideeffect.c | 4 ++++ 1 file changed, 4 insertions(+)
net/sctp/sm_sideeffect.c +4 -0
@@ -1321,6 +1321,10 @@ static int sctp_cmd_interpreter(enum sctsctp_outq_uncork (&asoc->outqueue, gfp); local_cork =0 ; } +/* No chunk left in this packet may use this asoc. */ +if (event_type ==SCTP_EVENT_T_CHUNK && + chunk->asoc == asoc) + chunk->pdiscard =1 ;/* Delete the current association. */ sctp_cmd_delete_tcb (commands, asoc); asoc =NULL ;
Greg Kroah-Hartman
maintainerPATCH 131/798 sctp: drop a chunk if its transport was removed
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
commit 03a9d10ecf71f54b2af8020935f2033d4a132be5 upstream.
sctp_rcv() resolves the transport once per packet and leaves it in chunk->transport. The lookup reference, or the one sctp_add_backlog() takes if the socket is owned by userspace, keeps it around until the chunk has been processed.
An authenticated ASCONF DEL-IP can remove it in the meantime. sctp_assoc_rm_peer() takes the transport out of the association and calls sctp_transport_free(), which tags it dead and drops the reference the association held. There is a window on both paths: the packet can sit on the socket backlog, and on the direct path the lookup completes before bh_lock_sock().
The DATA chunk in that packet puts the removed transport back into asoc->peer.last_data_from. Once the packet is done that reference goes away and the transport is freed by RCU, so the next delayed SACK carries the pointer into the SACK chunk and sctp_outq_select_transport() reads the freed transport's state.
Drop the chunk in sctp_inq_push(), next to the existing rcvr->dead check. Both paths reach it with the association's socket lock held. The peer retransmits it.
--- net/sctp/inqueue.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
net/sctp/inqueue.c +5 -2
@@ -63,8 +63,11 @@ void sctp_inq_free(struct sctp_inq *queu*/ void sctp_inq_push (struct sctp_inq *q,struct sctp_chunk *chunk) { -/* Directly call the packet handling routine. */ -if (chunk->rcvr->dead) { +/* Directly call the packet handling routine. Drop the chunk if the +* receiver or the transport it was looked up on is gone. +*/ +if (chunk->rcvr->dead || + (chunk->transport && chunk->transport->dead)) {sctp_chunk_free (chunk);return ; }
Greg Kroah-Hartman
maintainerPATCH 132/798 sctp: fix NULL deref on untransmitted RECONF completion
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 2db9bfa3e27bdea15e05ea70b56bad3d21e570ec upstream.
sctp_process_strreset_outreq(), sctp_process_strreset_addstrm_out() and sctp_process_strreset_resp() complete a pending stream reconfiguration request by stopping the reconf timer on the transport it was sent on:
t = asoc->strreset_chunk->transport; if (timer_delete(&t->reconf_timer)) sctp_transport_put(t);
chunk->transport is assigned by __sctp_packet_append_chunk() when the chunk is appended to an outbound packet, and sctp_outq_flush_ctrl() arms the reconf timer at that same point. A request already published in asoc->strreset_chunk but not yet transmitted has neither, so completing it dereferences NULL.
Two ways to get there. sctp_send_asconf_del_ip() sets asoc->src_out_of_asoc_ok without sending anything when the address being removed is the association's last one, and sctp_outq_flush_ctrl() then leaves every non-ASCONF control chunk queued; as only sctp_process_asconf_ack() clears that flag, it persists. An unprivileged process that removes such an address and then asks for a stream reset panics the kernel from softirq. A peer needs neither ASCONF nor local
help: sctp_cmd_interpreter() uncorks the outqueue only once the whole packet has been processed, so a reply built while walking a RECONF chunk stays untransmitted for the rest of that walk, and one RECONF chunk carrying [Incoming SSN Reset Request, Outgoing SSN Reset Request, Response] -- or two RECONF chunks in one packet -- reaches the same dereference.
KASAN: null-ptr-deref in range [0x00000000000001e8-0x00000000000001ef] RIP: 0010:timer_delete+0x67/0x110 Call Trace: <IRQ> sctp_process_strreset_addstrm_out (net/sctp/stream.c:832) sctp_sf_do_reconf (net/sctp/sm_statefuns.c:4212) sctp_do_sm (net/sctp/sm_sideeffect.c:1172) sctp_assoc_bh_rcv (net/sctp/associola.c:1044) sctp_rcv (net/sctp/input.c:243) ip_local_deliver (net/ipv4/ip_input.c:262) process_backlog (net/core/dev.c:6680) </IRQ>
A response can only acknowledge a request that was actually sent, so do not match asoc->strreset_chunk while chunk->transport is NULL. Guarding the lookup covers all three completion sites.
--- net/sctp/stream.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/sctp/stream.c +1 -1
@@ -488,7 +488,7 @@ static struct sctp_paramhdr *sctp_chunk_struct sctp_reconf_chunk *hdr;union sctp_params param; -if (!chunk) +if (!chunk || !chunk->transport)return NULL ; hdr = (struct sctp_reconf_chunk *)chunk->chunk_hdr;
Greg Kroah-Hartman
maintainerPATCH 133/798 sctp: distinguish sequence zero from wildcard in reconf lookup
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jun Yang <[email protected]>
commit 63f44178f0a0f86060c9b576d6efab8a3ffa403e upstream.
Zero is a valid response sequence after strreset_outseq wraps, but sctp_chunk_lookup_strreset_param() currently treats it as a wildcard.
Add match_seq so response lookups match zero exactly while the one type-only lookup can still ignore the sequence.
--- net/sctp/stream.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-)
net/sctp/stream.c +6 -5
@@ -482,7 +482,7 @@ out:static struct sctp_paramhdr *sctp_chunk_lookup_strreset_param (struct sctp_association *asoc,__be32 resp_seq, -__be16 type) +__be16 type,bool match_seq) {struct sctp_chunk *chunk = asoc->strreset_chunk;struct sctp_reconf_chunk *hdr;
@@ -499,7 +499,7 @@ static struct sctp_paramhdr *sctp_chunk_*/ struct sctp_strreset_tsnreq *req = param.v; -if ((!resp_seq || req->request_seq == resp_seq) && +if ((!match_seq || req->request_seq == resp_seq) && (!type || type == req->param_hdr.type))return param.v; }
@@ -564,7 +564,7 @@ struct sctp_chunk *sctp_process_strresetif (asoc->strreset_chunk) {if (!sctp_chunk_lookup_strreset_param ( asoc, outreq->response_seq, -SCTP_PARAM_RESET_IN_REQUEST )) { +SCTP_PARAM_RESET_IN_REQUEST , true)) {/* same process with outstanding isn't 0 */ result =SCTP_STRRESET_ERR_IN_PROGRESS ; goto out;
@@ -816,7 +816,7 @@ struct sctp_chunk *sctp_process_strresetif (asoc->strreset_chunk) {if (!sctp_chunk_lookup_strreset_param ( - asoc,0 ,SCTP_PARAM_RESET_ADD_IN_STREAMS )) { + asoc,0 ,SCTP_PARAM_RESET_ADD_IN_STREAMS , false)) {/* same process with outstanding isn't 0 */ result =SCTP_STRRESET_ERR_IN_PROGRESS ; goto out;
@@ -927,7 +927,8 @@ struct sctp_chunk *sctp_process_strresetstruct sctp_paramhdr *req;__u32 result; - req =sctp_chunk_lookup_strreset_param (asoc, resp->response_seq,0 ); + req =sctp_chunk_lookup_strreset_param (asoc, resp->response_seq,0 , + true);if (!req)return NULL ;
Greg Kroah-Hartman
maintainerPATCH 134/798 sctp: fix stream->outcnt underflow on duplicate RECONF responses
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jun Yang <[email protected]>
commit 3faf13aff243ca9f78d08b1a2956ef5a6fc77b6e upstream.
A cached RECONF chunk may contain more than one request parameter. A duplicate response can therefore find and process the same ADD_OUT request again while another parameter is still outstanding, rolling back outcnt twice and possibly underflowing it.
Track outstanding request types as bits and clear each bit after its first response. Later responses for the same request are then ignored.
--- include/net/sctp/structs.h | 2 +- net/sctp/stream.c | 39 ++++++++++++++++++++++++++++----------- 2 files changed, 29 insertions(+), 12 deletions(-)
include/net/sctp/structs.h +1 -1
@@ -2062,7 +2062,7 @@ struct sctp_association { force_delay:1 ;__u8 strreset_enable; -__u8 strreset_outstanding;/* request param count on the fly */ +__u8 strreset_outstanding;/* request param bitmask on the fly */ __u32 strreset_outseq;/* Update after receiving response */ __u32 strreset_inseq;/* Update after receiving request */
net/sctp/stream.c +28 -11
@@ -22,6 +22,15 @@#include <net/sctp/sm.h> #include <net/sctp/stream_sched.h> +#define SCTP_STRRESET_MASK (type) \ + BIT(ntohs(type) - ntohs(SCTP_PARAM_RESET_OUT_REQUEST)) +#define SCTP_STRRESET_TEST (asoc, type) \ + ((asoc)->strreset_outstanding & SCTP_STRRESET_MASK(type)) +#define SCTP_STRRESET_SET (asoc, type) \ + ((asoc)->strreset_outstanding |= SCTP_STRRESET_MASK(type)) +#define SCTP_STRRESET_CLEAR (asoc, type) \ + ((asoc)->strreset_outstanding &= ~SCTP_STRRESET_MASK(type)) +static void sctp_stream_shrink_out (struct sctp_stream *stream,__u16 outcnt) {struct sctp_association *asoc;
@@ -372,7 +381,10 @@ int sctp_send_reset_streams(struct sctp_ goto out; } - asoc->strreset_outstanding = out + in; +if (out) +SCTP_STRRESET_SET (asoc,SCTP_PARAM_RESET_OUT_REQUEST ); +if (in) +SCTP_STRRESET_SET (asoc,SCTP_PARAM_RESET_IN_REQUEST ); out:return retval;
@@ -417,7 +429,7 @@ int sctp_send_reset_assoc(struct sctp_asreturn retval; } - asoc->strreset_outstanding =1 ; +SCTP_STRRESET_SET (asoc,SCTP_PARAM_RESET_TSN_REQUEST );return 0 ; }
@@ -474,7 +486,10 @@ int sctp_send_add_streams(struct sctp_as goto out; } - asoc->strreset_outstanding = !!out + !!in; +if (out) +SCTP_STRRESET_SET (asoc,SCTP_PARAM_RESET_ADD_OUT_STREAMS ); +if (in) +SCTP_STRRESET_SET (asoc,SCTP_PARAM_RESET_ADD_IN_STREAMS ); out:return retval;
@@ -564,13 +579,14 @@ struct sctp_chunk *sctp_process_strresetif (asoc->strreset_chunk) {if (!sctp_chunk_lookup_strreset_param ( asoc, outreq->response_seq, -SCTP_PARAM_RESET_IN_REQUEST , true)) { +SCTP_PARAM_RESET_IN_REQUEST , true) || + !SCTP_STRRESET_TEST (asoc,SCTP_PARAM_RESET_IN_REQUEST )) {/* same process with outstanding isn't 0 */ result =SCTP_STRRESET_ERR_IN_PROGRESS ; goto out; } - asoc->strreset_outstanding--; +SCTP_STRRESET_CLEAR (asoc,SCTP_PARAM_RESET_IN_REQUEST ); asoc->strreset_outseq++;if (!asoc->strreset_outstanding) {
@@ -669,7 +685,7 @@ struct sctp_chunk *sctp_process_strresetSCTP_SO (stream, i)->state =SCTP_STREAM_CLOSED ; asoc->strreset_chunk = chunk; - asoc->strreset_outstanding =1 ; +SCTP_STRRESET_SET (asoc,SCTP_PARAM_RESET_OUT_REQUEST );sctp_chunk_hold (asoc->strreset_chunk); result =SCTP_STRRESET_PERFORMED ;
@@ -816,13 +832,14 @@ struct sctp_chunk *sctp_process_strresetif (asoc->strreset_chunk) {if (!sctp_chunk_lookup_strreset_param ( - asoc,0 ,SCTP_PARAM_RESET_ADD_IN_STREAMS , false)) { + asoc,0 ,SCTP_PARAM_RESET_ADD_IN_STREAMS , false) || + !SCTP_STRRESET_TEST (asoc,SCTP_PARAM_RESET_ADD_IN_STREAMS )) {/* same process with outstanding isn't 0 */ result =SCTP_STRRESET_ERR_IN_PROGRESS ; goto out; } - asoc->strreset_outstanding--; +SCTP_STRRESET_CLEAR (asoc,SCTP_PARAM_RESET_ADD_IN_STREAMS ); asoc->strreset_outseq++;if (!asoc->strreset_outstanding) {
@@ -899,7 +916,7 @@ struct sctp_chunk *sctp_process_strreset goto out; asoc->strreset_chunk = chunk; - asoc->strreset_outstanding =1 ; +SCTP_STRRESET_SET (asoc,SCTP_PARAM_RESET_ADD_OUT_STREAMS );sctp_chunk_hold (asoc->strreset_chunk); stream->outcnt = outcnt;
@@ -929,7 +946,7 @@ struct sctp_chunk *sctp_process_strreset req =sctp_chunk_lookup_strreset_param (asoc, resp->response_seq,0 , true); -if (!req) +if (!req || !SCTP_STRRESET_TEST (asoc, req->type))return NULL ; result =ntohl (resp->result);
@@ -1079,7 +1096,7 @@ struct sctp_chunk *sctp_process_strreset nums, 0, GFP_ATOMIC); } - asoc->strreset_outstanding--; +SCTP_STRRESET_CLEAR (asoc, req->type); asoc->strreset_outseq++;/* remove everything for this reconf request */
Greg Kroah-Hartman
maintainerPATCH 135/798 power: supply: cros_usbpd-charger: bound the EC-reported port count
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 48355ce49359740f52e94d3623f6fc557ce341f0 upstream.
cros_usbpd_charger_probe() reads two port counts from the EC and uses one of them, num_charger_ports, as the loop bound when populating a fixed-size array:
struct port_data *ports[EC_USB_PD_MAX_PORTS]; /* 8 entries */ ... for (i = 0; i < charger->num_charger_ports; i++) charger->ports[charger->num_registered_psy++] = port;
Both num_usbpd_ports (from EC_CMD_USB_PD_PORTS) and num_charger_ports (from EC_CMD_CHARGE_PORT_COUNT) are u8 values reported by the EC. The only validation is a sanity check that compares the two EC-reported values against each other:
if (num_charger_ports < num_usbpd_ports || num_charger_ports > num_usbpd_ports + 1) return -EPROTO;
It never checks either count against EC_USB_PD_MAX_PORTS, the size of the ports[] array. A malfunctioning, malicious or compromised EC that reports num_usbpd_ports == num_charger_ports == N for any N > 8 (for example both 255) passes this check, and the loop then writes N pointers into the 8-entry ports[] array embedded in the devm_kzalloc()'d charger_data, overflowing it by up to 255 - 8 = 247 entries (~1976 bytes): a slab out-of-bounds write.
Reject a port count larger than the ports[] array can hold.
--- drivers/power/supply/cros_usbpd-charger.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/power/supply/cros_usbpd-charger.c +5 -2
@@ -600,10 +600,13 @@ static int cros_usbpd_charger_probe(stru/* * Sanity checks on the number of ports: -* there should be at most 1 dedicated port +* there should be at most 1 dedicated port, and the count must +* not exceed the maximum number of supported ports +* (EC_USB_PD_MAX_PORTS). */ if (charger->num_charger_ports < charger->num_usbpd_ports || - charger->num_charger_ports > (charger->num_usbpd_ports +1 )) { + charger->num_charger_ports > (charger->num_usbpd_ports +1 ) || + charger->num_charger_ports >EC_USB_PD_MAX_PORTS ) {dev_err (dev,"Unexpected number of charge port count\n" ); ret = -EPROTO ; goto fail_nowarn;
Greg Kroah-Hartman
maintainerPATCH 136/798 power: supply: cros_usbpd: Limit port counts to EC_USB_PD_MAX_PORTS
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jameson Thies <[email protected]>
commit 657cd3a42e937276262c0a8ae6b01a87004309de upstream.
Currently the cros_usbpd-charger driver probe iterates based on raw charger port count returned by the embedded controller. The only check is against the number of USB PD ports which the embedded controller also defines. A malicious embedded controller could return an inaccurate port count (up to 255) resulting in an out of bounds write and subsequent memory corruption.
Update helper functions in cros_usbpd-charger to limit port counts to EC_USB_PD_MAX_PORTS.
--- drivers/power/supply/cros_usbpd-charger.c | 10 ++++++++++ 1 file changed, 10 insertions(+)
drivers/power/supply/cros_usbpd-charger.c +10 -0
@@ -136,6 +136,11 @@ static int cros_usbpd_charger_get_num_poif (ret <0 )return ret; +if (resp.port_count >EC_USB_PD_MAX_PORTS ) { +dev_warn (charger->dev,"Charge port count out of bounds\n" ); +return EC_USB_PD_MAX_PORTS ; + } +return resp.port_count; }
@@ -149,6 +154,11 @@ static int cros_usbpd_charger_get_usbpd_if (ret <0 )return ret; +if (resp.num_ports >EC_USB_PD_MAX_PORTS ) { +dev_warn (charger->dev,"USB PD port count out of bounds\n" ); +return EC_USB_PD_MAX_PORTS ; + } +return resp.num_ports; }
Greg Kroah-Hartman
maintainerPATCH 137/798 power: supply: lp8727: fix use-after-free in lp8727_release_irq()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit ceb6ac43b0f591722401922ceb958ce2616935e0 upstream.
lp8727_isr_func(), the threaded IRQ handler, is the only caller that arms pchg->work via schedule_delayed_work(). lp8727_release_irq() currently cancels the work before freeing the IRQ, so an IRQ delivered in between can re-arm the work through the threaded handler. After .remove returns the devm layer frees pchg while lp8727_delayed_func() may still run and dereference it.
Free the IRQ first so the threaded handler is quiesced and can no longer queue work, then cancel the delayed work to drain the final generation.
This issue was found by an in-house static analysis tool.
--- drivers/power/supply/lp8727_charger.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/power/supply/lp8727_charger.c +2 -2
@@ -280,10 +280,10 @@ static int lp8727_setup_irq(struct lp872static void lp8727_release_irq (struct lp8727_chg *pchg) { -cancel_delayed_work_sync (&pchg->work); -if (pchg->irq)free_irq (pchg->irq, pchg); + +cancel_delayed_work_sync (&pchg->work); }static enum power_supply_property lp8727_charger_prop[] = {
Greg Kroah-Hartman
maintainerPATCH 138/798 power: supply: max17040: synchronize work cancellation on suspend
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jianing Li <[email protected]>
commit 86a3a8a926aa5969c329d1df2d3259f189961bbc upstream.
max17040_work() requeues itself after every poll. cancel_delayed_work() only cancels a pending instance and does not wait for a callback that is already running.
If system suspend races with the polling callback, the callback can continue accessing the fuel gauge and requeue itself after the suspend callback returns.
Use cancel_delayed_work_sync() to ensure polling is quiesced before suspend completes.
--- drivers/power/supply/max17040_battery.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/power/supply/max17040_battery.c +1 -1
@@ -566,7 +566,7 @@ static int max17040_suspend(struct devic// disable soc alert to prevent wakeup max17040_set_soc_alert (chip,0 ); else - cancel_delayed_work(&chip->work); + cancel_delayed_work_sync(&chip->work);if (client->irq &&device_may_wakeup (dev))enable_irq_wake (client->irq);
Greg Kroah-Hartman
maintainerPATCH 139/798 s390/dasd: Do not complete a failed ESE read as successful
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Haberland <[email protected]>
commit cddb447c62466f3076938ce120028d7b591f9f37 upstream.
dasd_int_handler() completes an NRF read of an unallocated ESE track by calling ese_read() and unconditionally marking the request DASD_CQR_SUCCESS. dasd_eckd_ese_read() can return an error before it has zeroed the destination buffer: a failed sense-data parse or a current track outside the requested range both return early, leaving the destination pages untouched. The request is still completed successfully, so the block layer is handed stale / uninitialized memory instead of zeros.
Check the ese_read() return value and fail the request through the normal error path instead of forcing DASD_CQR_SUCCESS.
--- drivers/s390/block/dasd.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/s390/block/dasd.c +4 -2
@@ -1803,8 +1803,10 @@ void dasd_int_handler(struct ccw_devicereturn ; }if (rq_data_dir (req) ==READ ) { - device->discipline->ese_read (cqr, irb); - cqr->status =DASD_CQR_SUCCESS ; +if (device->discipline->ese_read (cqr, irb)) + cqr->status =DASD_CQR_ERROR ; +else + cqr->status =DASD_CQR_SUCCESS ; cqr->stopclk = now;dasd_device_clear_timer (device);dasd_schedule_device_bh (device);
Greg Kroah-Hartman
maintainerPATCH 140/798 s390/dasd: Guard sysfs discipline callbacks against unallocated private data
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Haberland <[email protected]>
commit 2a1780f9fc2493bd34c418a0be6fc58943afcecf upstream.
Several sysfs show/store handlers call a discipline callback that dereferences device->private, either directly or through the DASD_DEFINE_ATTR() macro. During dasd_generic_set_online() the discipline is assigned before check_device() allocates device->private, so an unprivileged read of one of these world-readable attributes in that window dereferences a NULL pointer and panics.
Guard the dereference inside each callback that actually touches device->private.
--- drivers/s390/block/dasd_eckd.c | 40 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-)
drivers/s390/block/dasd_eckd.c +38 -2
@@ -1464,6 +1464,8 @@ static void dasd_eckd_reset_path(structstruct dasd_eckd_private *private = device->private;unsigned long flags; +if (!private) +return ;if (!private->fcx_max_data) private->fcx_max_data =get_fcx_max_data (device);spin_lock_irqsave (get_ccwdev_lock (device->cdev), flags);
@@ -1619,6 +1621,9 @@ static int dasd_eckd_is_ese(struct dasd_ {struct dasd_eckd_private *private = device->private; +if (!private) +return 0 ; +return private->vsq.vol_info.ese; }
@@ -1626,6 +1631,9 @@ static int dasd_eckd_ext_pool_id(struct {struct dasd_eckd_private *private = device->private; +if (!private) +return 0 ; +return private->vsq.extent_pool_id; }
@@ -1639,6 +1647,9 @@ static int dasd_eckd_space_configured(ststruct dasd_eckd_private *private = device->private;int rc; +if (!private) +return 0 ; + rc =dasd_eckd_read_vol_info (device);return rc ? : private->vsq.space_configured;
@@ -1653,6 +1664,9 @@ static int dasd_eckd_space_allocated(strstruct dasd_eckd_private *private = device->private;int rc; +if (!private) +return 0 ; + rc =dasd_eckd_read_vol_info (device);return rc ? : private->vsq.space_allocated;
@@ -1662,6 +1676,9 @@ static int dasd_eckd_logical_capacity(st {struct dasd_eckd_private *private = device->private; +if (!private) +return 0 ; +return private->vsq.logical_capacity; }
@@ -1804,7 +1821,11 @@ static int dasd_eckd_read_ext_pool_info(static int dasd_eckd_ext_size (struct dasd_device *device) {struct dasd_eckd_private *private = device->private; -struct dasd_ext_pool_sum eps = private->eps; +struct dasd_ext_pool_sum eps; + +if (!private) +return 0 ; + eps = private->eps;if (!eps.flags.extent_size_valid)return 0 ;
@@ -1820,6 +1841,9 @@ static int dasd_eckd_ext_pool_warn_thrsh {struct dasd_eckd_private *private = device->private; +if (!private) +return 0 ; +return private->eps.warn_thrshld; }
@@ -1827,6 +1851,9 @@ static int dasd_eckd_ext_pool_cap_at_war {struct dasd_eckd_private *private = device->private; +if (!private) +return 0 ; +return private->eps.flags.capacity_at_warnlevel; }
@@ -1837,6 +1864,9 @@ static int dasd_eckd_ext_pool_oos(struct {struct dasd_eckd_private *private = device->private; +if (!private) +return 0 ; +return private->eps.flags.pool_oos; }
@@ -5966,8 +5996,11 @@ static int dasd_eckd_query_host_access(sstruct ccw1 *ccw;int rc; +if (!private) +return -ENODEV ; +/* not available for HYPER PAV alias devices */ -if (!device->block && private->lcu->pav ==HYPER_PAV ) +if (!device->block && private->lcu && private->lcu->pav ==HYPER_PAV )return -EOPNOTSUPP ;/* may not be supported by the storage server */
@@ -6607,6 +6640,9 @@ static int dasd_eckd_hpf_enabled(struct {struct dasd_eckd_private *private = device->private; +if (!private) +return 0 ; +return private->fcx_max_data ?1 :0 ; }
Greg Kroah-Hartman
maintainerPATCH 141/798 s390/dasd: Propagate partial completion length across ERP recovery
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stefan Haberland <[email protected]>
commit 6fb5ba2e7e43173a3761e46f091070a8185efa14 upstream.
dasd_default_erp_postaction() copies the timing and device state from the finished ERP request back to the original request but drops proc_bytes. A request that was partially completed, an ESE read of a not-yet-allocated track returns fewer bytes than requested, and then recovered through the ERP chain loses its partial-completion length. __dasd_cleanup_cqr() then sees proc_bytes == 0 and completes the whole request instead of requeueing the remainder, silently returning zeroed data for the part that was never read.
Carry proc_bytes over to the original request like the other per-request state.
--- drivers/s390/block/dasd_erp.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/s390/block/dasd_erp.c +3 -0
@@ -127,6 +127,7 @@ struct dasd_ccw_req *dasd_default_erp_point success;unsigned long startclk, stopclk;struct dasd_device *startdev; +unsigned int proc_bytes;BUG_ON (cqr->refers ==NULL || cqr->function ==NULL );
@@ -134,6 +135,7 @@ struct dasd_ccw_req *dasd_default_erp_po startclk = cqr->startclk; stopclk = cqr->stopclk; startdev = cqr->startdev; + proc_bytes = cqr->proc_bytes;/* free all ERPs - but NOT the original cqr */ while (cqr->refers !=NULL ) {
@@ -151,6 +153,7 @@ struct dasd_ccw_req *dasd_default_erp_po cqr->startclk = startclk; cqr->stopclk = stopclk; cqr->startdev = startdev; + cqr->proc_bytes = proc_bytes;if (success) cqr->status =DASD_CQR_DONE ;else {
Greg Kroah-Hartman
maintainerPATCH 142/798 PCI: Fix 32-bit config write in Intel PCH Root Port MPC ACS quirk
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mohamad Raizudeen <[email protected]>
commit 23d7eed5974989de56273c964d7e510e4aad91e8 upstream.
pci_quirk_enable_intel_rp_mpc_acs() reads a 32-bit DWORD from the MPC register, sets bit 26 (INTEL_MPC_REG_IRBNCE), but it writes it back using pci_write_config_word().
Because bit 26 resides in the upper 16 bits of the 32-bit register, a 16-bit write drops the newly set bit. The quirk logs that it is enabling IRBNCE, but the hardware never actually receives the command.
Use pci_write_config_dword() to ensure the full 32-bit value is written back to the hardware.
--- drivers/pci/quirks.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/quirks.c +1 -1
@@ -5169,7 +5169,7 @@ static void pci_quirk_enable_intel_rp_mpif (!(mpc &INTEL_MPC_REG_IRBNCE )) {pci_info (dev,"Enabling MPC IRBNCE\n" ); mpc |=INTEL_MPC_REG_IRBNCE ; -pci_write_config_word (dev,INTEL_MPC_REG , mpc); +pci_write_config_dword (dev,INTEL_MPC_REG , mpc); } }
Greg Kroah-Hartman
maintainerPATCH 143/798 PCI: meson: Fix GPIO state while requesting PERST#
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ronald Claveau <[email protected]>
commit 40fb390cbcc11797c44c16dabdf763ec87643671 upstream.
Meson devicetree defines the PERST# GPIO as 'reset' GPIO. Commit 4d3186a525b3 ("PCI: amlogic: Fix reset assertion via gpio descriptor") inverted the PERST# assertion logic to use proper GPIO descriptor semantics and moved the polarity configuration to the device tree as GPIO_ACTIVE_LOW. However, the initial PERST# GPIO state "GPIOD_OUT_LOW" was not updated accordingly.
This results in the enumeration failure of the endpoint devices as PERST# would get deasserted while requesting the GPIO even before power and REFCLK becomes stable.
Without this fix:
ahci 0000:01:00.0: enabling device (0000 -> 0002) ahci 0000:01:00.0: SSS flag set, parallel bus scan disabled ahci 0000:01:00.0: Controller reset failed (0xffffffff) ahci 0000:01:00.0: probe with driver ahci failed with error -5
With this fix:
ahci 0000:01:00.0: enabling device (0000 -> 0002)
ahci 0000:01:00.0: AHCI vers 0001.0300, 32 command slots, 6 Gbps, SATA mode ahci 0000:01:00.0: 1/1 ports implemented (port mask 0x1)
ahci 0000:01:00.0: flags: 64bit ncq led clo only pio ccc
Change the GPIO request flag from GPIOD_OUT_LOW to GPIOD_OUT_HIGH to get the right behaviour.
--- drivers/pci/controller/dwc/pci-meson.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/controller/dwc/pci-meson.c +1 -1
@@ -448,7 +448,7 @@ static int meson_pcie_probe(struct platfreturn PTR_ERR (mp->phy); } - mp->reset_gpio =devm_gpiod_get (dev,"reset" ,GPIOD_OUT_LOW ); + mp->reset_gpio =devm_gpiod_get (dev,"reset" ,GPIOD_OUT_HIGH );if (IS_ERR (mp->reset_gpio)) {dev_err (dev,"get reset gpio failed\n" );return PTR_ERR (mp->reset_gpio);
Greg Kroah-Hartman
maintainerPATCH 144/798 PCI/sysfs: Avoid spurious runtime PM wakeup on config space accesses
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
commit b14b2bab88d7099ab4447560cbe4b40945e5c069 upstream.
Currently, the boundary checks in pci_read_config() and pci_write_config() reject only offsets beyond the effective configuration space size.
An access at an offset exactly equal to that size passes the check, has its length clamped to zero, and then invokes pci_config_pm_runtime_get() and pci_config_pm_runtime_put() around transfer blocks that do nothing.
This is a problem because pci_config_pm_runtime_get() synchronously resumes the upstream bridge through pm_runtime_get_sync() and resumes the device itself through pm_runtime_resume() when it is in D3cold, only for the handler to return zero immediately afterwards. Such a spurious wakeup wastes power and adds needless resume latency.
The sysfs core already clamps accesses against the attribute size set through the bin_size() callback, which reports either 256 or 4096 bytes. As such, the affected accesses are reads at offset 64 (or 128 for CardBus devices) through files opened without CAP_SYS_ADMIN, and reads and writes at the exact configuration space size on devices where a quirk sets a non-standard size.
Reject accesses at the boundary offset as well, so they return early before any runtime PM involvement, matching the procfs implementations in proc_bus_pci_read() and proc_bus_pci_write().
The value returned to userspace at these offsets remains zero, so the change is not visible to userspace.
--- drivers/pci/pci-sysfs.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/pci/pci-sysfs.c +2 -2
@@ -722,7 +722,7 @@ static ssize_t pci_read_config(struct fielse if (dev->hdr_type ==PCI_HEADER_TYPE_CARDBUS ) size =128 ; -if (off > size) +if (off >= size)return 0 ;if (off + count > size) { size -= off;
@@ -798,7 +798,7 @@ static ssize_t pci_write_config(struct fif (ret)return ret; -if (off > dev->cfg_size) +if (off >= dev->cfg_size)return 0 ;if (off + count > dev->cfg_size) { size = dev->cfg_size - off;
Greg Kroah-Hartman
maintainerPATCH 145/798 PCI/proc: Avoid spurious runtime PM wakeup on config space accesses
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
commit 4ff664a81d729b37f2eb65de80a670abfb61c9a0 upstream.
Currently, proc_bus_pci_read() and proc_bus_pci_write() do not return early for zero-length configuration space accesses at valid offsets.
Such an access invokes pci_config_pm_runtime_get() and pci_config_pm_runtime_put() around transfer blocks that do nothing.
This is a problem because pci_config_pm_runtime_get() synchronously resumes the upstream bridge through pm_runtime_get_sync(), and resumes the device itself through pm_runtime_resume() when it is in D3cold, only for the handler to return zero immediately afterwards. Such a spurious wakeup wastes power and adds needless resume latency.
The sysfs core already returns early for in-range zero-length binary attribute accesses before pci_read_config() or pci_write_config() is invoked. In contrast, the VFS forwards zero-length requests to the procfs callbacks, where they continue into runtime PM handling.
Return early from proc_bus_pci_read() and proc_bus_pci_write() when nbytes is zero, before any runtime PM involvement.
The value returned to userspace at these offsets remains zero, so the change is not visible to userspace.
--- drivers/pci/proc.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/pci/proc.c +6 -0
@@ -45,6 +45,9 @@ static ssize_t proc_bus_pci_read(structelse size =64 ; +if (!nbytes) +return 0 ; +if (pos >= size)return 0 ;if (nbytes >= size)
@@ -122,6 +125,9 @@ static ssize_t proc_bus_pci_write(structif (ret)return ret; +if (!nbytes) +return 0 ; +if (pos >= size)return 0 ;if (nbytes >= size)
Greg Kroah-Hartman
maintainerPATCH 146/798 PCI/proc: Use file_ns_capable() when checking config space read access
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Krzysztof Wilczyński <[email protected]>
commit f82f53e75eff382fc8f56b73279b54f7cf5a5c65 upstream.
proc_bus_pci_read() decides how much of the config space is readable based on capable(CAP_SYS_ADMIN), which checks the credentials of the task calling read(), not the credentials of the process that opened the file.
The sysfs equivalent, pci_read_config(), has checked the credentials of the opening process since commit de139a339395 ("pci: check caps from sysfs file open to read device dependent config space"), so a privileged process can open the config space file and pass the file descriptor to an unprivileged process (for example, a process running a KVM guest with an assigned device), which can then read the entire config space. The check was subsequently routed through the LSM framework in commit 47970b1b2aa6 ("pci:
use security_capable() when checking capablities during config space read") and converted to the dedicated helper in commit ab0fa82b2df9 ("pci-sysfs:
use proper file capability helper function").
Thus, the two interfaces check the same capability against different credentials. Checking the credentials of the task calling read() makes the outcome depend on who reads rather than who opened, so the restriction is bypassed whenever a more privileged process reads through the descriptor. Checking the credentials recorded in file->f_cred settles the decision at open() time and ties it to the file, where it cannot change with the caller.
Use file_ns_capable() to check CAP_SYS_ADMIN against the credentials in effect when the file was opened, bringing the procfs interface in line with the sysfs behaviour.
As a result, a file descriptor opened by a privileged process and passed to an unprivileged one now allows the entire config space to be read through procfs, matching sysfs.
--- drivers/pci/proc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/pci/proc.c +1 -1
@@ -38,7 +38,7 @@ static ssize_t proc_bus_pci_read(struct* undefined locations (think of Intel PIIX4 as a typical example). */ -if (capable (CAP_SYS_ADMIN )) +if (file_ns_capable (file, &init_user_ns,CAP_SYS_ADMIN )) size = dev->cfg_size;else if (dev->hdr_type ==PCI_HEADER_TYPE_CARDBUS ) size =128 ;
Greg Kroah-Hartman
maintainerPATCH 147/798 iommu/vt-d: Fix no_iommu to disable platform opt-in
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kevin Tian <[email protected]>
commit 219cc978d69ce9b538d0d73936c569d4ca5b0a24 upstream.
If user explicitly requests to disable iommu (via "iommu=off" or "intel_iommu=off"), there is no reason to force enabling it due to platform opt-in (for external-facing devices). User should be aware of any security implication of doing so.
"intel_iommu=off" implements this policy by setting no_platform_optin to skip platform opt-in in platform_optin_force_iommu().
However, "iommu=off" (no_iommu=1) doesn't set no_platform_optin hence is broken in this aspect:
- detect_intel_iommu() doesn't request ACS if no_iommu=1
- platform_optin_force_iommu() forces iommu on if external-facing devices exist and no_platform_optin is not set
This leads to a bad configuration with ACS disabled while DMA remapping is enabled.
Instead of setting no_platform_optin (will soon be removed) for no_iommu=1, directly check no_iommu in platform_optin_force_iommu().
--- drivers/iommu/intel/iommu.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-)
drivers/iommu/intel/iommu.c +3 -3
@@ -4903,10 +4903,11 @@ static inline bool has_external_pci(voidstatic int __init platform_optin_force_iommu (void ) { -if (!dmar_platform_optin () || no_platform_optin || !has_external_pci ()) +if (no_iommu || !dmar_platform_optin () || no_platform_optin || + !has_external_pci ())return 0 ; -if (no_iommu || dmar_disabled) +if (dmar_disabled)pr_info ("Intel-IOMMU force enabled due to platform opt in\n" );/*
@@ -4917,7 +4918,6 @@ static int __init platform_optin_force_iiommu_set_default_passthrough (false); dmar_disabled =0 ; - no_iommu =0 ;return 1 ; }
Greg Kroah-Hartman
maintainerPATCH 148/798 mmc: via-sdmmc: stop card-detect handling on probe failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fan Wu <[email protected]>
commit 088eaa92fcebaa6b957ccf9635afdf39643a577d upstream.
request_irq() registers the SD card-detect interrupt and the probe enables it before mmc_add_host() runs. If mmc_add_host() fails, the error path only unmaps the registers and returns: the interrupt stays registered, so the handler keeps running against the host once it is freed. via_sdc_isr() dereferences sdhost and its MMIO base and schedules carddet_work, which via_sdc_card_detect() also runs against freed memory through its container_of() dereference.
Add a probe-error path that disables and frees the interrupt and cancels carddet_work before unmapping. carddet_work can re-enable the device interrupt via via_reset_pcictrl(), which restores PCIINTCTRL, so mask it again after cancelling the work.
This issue was found by an in-house static analysis tool and confirmed by manual code review.
--- drivers/mmc/host/via-sdmmc.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-)
drivers/mmc/host/via-sdmmc.c +7 -1
@@ -1156,10 +1156,16 @@ static int via_sd_probe(struct pci_dev * ret =mmc_add_host (mmc);if (ret) - goto unmap; + goto free_irq;return 0 ; +free_irq: +writeb (0x0 , sdhost->pcictrl_mmiobase +VIA_CRDR_PCIINTCTRL ); +free_irq (pcidev->irq, sdhost); +cancel_work_sync (&sdhost->carddet_work); +/* carddet_work may re-enable the interrupt via via_reset_pcictrl(). */ +writeb (0x0 , sdhost->pcictrl_mmiobase +VIA_CRDR_PCIINTCTRL ); unmap:iounmap (sdhost->mmiobase); free_mmc_host:
Greg Kroah-Hartman
maintainerPATCH 149/798 platform/chrome: sensorhub: Bound the EC-reported sensor number
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 833740a2333c2e4db4e02e3d0ffba04e8718a5f3 upstream.
Each EC FIFO event carries an 8-bit sensor number (in->sensor_num). cros_ec_sensorhub_ring_handler() validates the FIFO event count, the per-read count and the ring bound, but not the sensor number, which cros_ec_sensor_ring_process_event() then uses unchecked to index sensorhub->batch_state[] - allocated with only sensorhub->sensor_num entries. A sensor number of sensor_num or larger is an out-of-bounds read and write of batch_state[].
Validate the sensor number in the ring handler, where each event is read from the EC, and drop a malformed event before it is used.
--- drivers/platform/chrome/cros_ec_sensorhub_ring.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/platform/chrome/cros_ec_sensorhub_ring.c +8 -0
@@ -851,6 +851,14 @@ static void cros_ec_sensorhub_ring_handlfor (in = sensorhub->resp->fifo_read.data, j =0 ; j < number_data; j++, in++) { +/* Skip event if sensor_num from EC is out of bounds. */ +if (in->sensor_num >= sensorhub->sensor_num) { +dev_warn_ratelimited (sensorhub->dev, +"Invalid sensor number %u from EC\n" , + in->sensor_num); +continue ; + } + if (cros_ec_sensor_ring_process_event( sensorhub, fifo_info, fifo_timestamp,
Greg Kroah-Hartman
maintainerPATCH 150/798 interconnect: Fix use after free in icc_get() and of_icc_get_by_index()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kuan-Wei Chiu <[email protected]>
commit 25c7e242aca084fdc1098248194032317dca625d upstream.
In of_icc_get_by_index() and icc_get(), if the dynamic allocation for path->name fails via kasprintf(), the error handling path directly calls kfree(path) to free the path object and returns an error.
However, prior to this point, path_find() calls path_init(), which already links the path's requests into the req_list of the respective interconnect nodes via hlist_add_head(). Directly invoking kfree(path) leaves dangling pointers in the hlist. A subsequent call to icc_get() or icc_set_bw() will traverse or modify these corrupted lists, triggering a slab use afterfree.
KASAN report showing the vulnerability when reproducing via debugfs:
BUG: KASAN: slab-use-after-free in path_find+0x6f8/0xcfc Write of size 8 at addr fff000000d43f748 by task sh/1 ... Call trace: kasan_report+0xac/0xfc path_find+0x6f8/0xcfc icc_get+0x148/0x380 icc_get_set+0xf8/0x2d0 ... Freed by task 1: kfree+0x1a0/0x4a4 icc_get+0x2cc/0x380 icc_get_set+0xf8/0x2d0
Fix this by replacing kfree(path) with the proper teardown function, icc_put(path), which safely removes the requests from the req_list using hlist_del() and drops the provider usage references before freeing the memory.
Additionally, in icc_get(), ensure that the icc_lock mutex is released prior to calling icc_put(path) to avoid a deadlock, as icc_put() internally acquires the same lock.
--- drivers/interconnect/core.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
drivers/interconnect/core.c +4 -3
@@ -507,7 +507,7 @@ struct icc_path *of_icc_get_by_index(str path->name =kasprintf (GFP_KERNEL ,"%s-%s" , src_data->node->name, dst_data->node->name);if (!path->name) { -kfree (path); +icc_put (path); path =ERR_PTR (-ENOMEM ); }
@@ -747,8 +747,9 @@ struct icc_path *icc_get(struct device * path->name =kasprintf (GFP_KERNEL ,"%s-%s" , src->name, dst->name);if (!path->name) { -kfree (path); - path =ERR_PTR (-ENOMEM ); +mutex_unlock (&icc_lock); +icc_put (path); +return ERR_PTR (-ENOMEM ); } out:mutex_unlock (&icc_lock);
Greg Kroah-Hartman
maintainerPATCH 151/798 ipmi: ipmb: validate write message length
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yousef Alhouseen <[email protected]>
commit 53637506884dbd5c91a89b1a3547d99d80f8ed2c upstream.
ipmb_write() read message fields before validating the length byte.
A zero or short write can read uninitialized stack bytes.
A length smaller than the SMBus header underflows the block write length.
Require a non-empty buffer and the minimum IPMB request length.
Also require the length byte plus payload before parsing the message.
Message-ID: <[email protected]>
--- drivers/char/ipmi/ipmb_dev_int.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/char/ipmi/ipmb_dev_int.c +3 -2
@@ -141,13 +141,14 @@ static ssize_t ipmb_write(struct file *fu8 msg[MAX_MSG_LEN ];ssize_t ret; -if (count >sizeof (msg)) +if (!count || count >sizeof (msg))return -EINVAL ;if (copy_from_user (&msg, buf, count))return -EFAULT ; -if (count < msg[0 ]) +if (msg[IPMB_MSG_LEN_IDX ] <IPMB_REQUEST_LEN_MIN || + count < (size_t )msg[IPMB_MSG_LEN_IDX ] +1 )return -EINVAL ; rq_sa =GET_7BIT_ADDR (msg[RQ_SA_8BIT_IDX ]);
Greg Kroah-Hartman
maintainerPATCH 152/798 ipmi: si: Fix NULL pointer dereference after failed registration
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Seiji Nishikawa <[email protected]>
commit 6d920a75df9a83ab096b3cde7a643b656e4fdfeb upstream.
try_smi_init() allocates new_smi->si_sm and later calls ipmi_register_smi_mod(), which maps to ipmi_add_smi().
During ipmi_add_smi(), the upper IPMI message handler obtains the initial BMC device information through __bmc_get_device_id(). This can fail if the BMC does not return a successful response to the Get Device ID command.
When the BMC returns a nonzero completion code, the device-id helper retries the command and eventually returns -EIO if the device ID still cannot be fetched.
On this failure path, ipmi_add_smi() logs "Unable to get the device id" and goes to out_err_started, where it invokes the lower driver's shutdown callback. try_smi_init() then logs the returned registration failure:
ipmi_si IPI0001:00: IPMI message handler: Unable to get the device id: -5 ipmi_si IPI0001:00: Unable to register device: error -5
For ipmi_si, the shutdown callback is shutdown_smi(), which cleans up the SI state machine data, frees smi_info->si_sm, and sets smi_info->si_sm and smi_info->intf to NULL.
However, intf->in_shutdown is not set on this failed-registration rollback path. Therefore, the asynchronous redo_bmc_reg work item can still retry BMC device-id probing after the lower driver has already cleared its SI state machine data. In the observed case, that retry path reached start_next_msg(), which passed the NULL smi_info->si_sm pointer to the selected KCS state machine handler:
BUG: unable to handle kernel NULL pointer dereference at 0000000000000000 Workqueue: events redo_bmc_reg [ipmi_msghandler] RIP: start_kcs_transaction+0x2c/0x190 [ipmi_si] Call Trace: start_next_msg+0x50/0x80 [ipmi_si] check_start_timer_thread.part.9+0x3b/0x50 [ipmi_si] sender+0x69/0x80 [ipmi_si] i_ipmi_request+0x2ac/0x9d0 [ipmi_msghandler] __get_device_id.isra.29+0xaa/0x180 [ipmi_msghandler] __bmc_get_device_id+0xef/0x950 [ipmi_msghandler] redo_bmc_reg+0x52/0x60 [ipmi_msghandler] process_one_work+0x1a7/0x360
Set intf->in_shutdown on the out_err_started path before invoking the lower driver's shutdown callback. This prevents later redo_bmc_reg retries from using an interface whose lower driver state has been cleaned up, and applies the same shutdown state to other IPMI interfaces as well.
Message-ID: <[email protected]>
--- drivers/char/ipmi/ipmi_msghandler.c | 1 + 1 file changed, 1 insertion(+)
drivers/char/ipmi/ipmi_msghandler.c +1 -0
@@ -3531,6 +3531,7 @@ int ipmi_add_smi(struct module * out_err_bmc_reg:ipmi_bmc_unregister (intf); out_err_started: + intf->in_shutdown = true;if (intf->handlers->shutdown) intf->handlers->shutdown (intf->send_info); out_err:
Greg Kroah-Hartman
maintainerPATCH 153/798 net/iucv: filter frames in afiucv_hs_rcv() by ingress device
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alexandra Winter <[email protected]>
commit 80230a18c164a4b5bbc048fe2768b219ac17bc5a upstream.
afiucv_hs_rcv() selects a socket from iucv_sk_list by matching four 8-byte name fields in the transport header alone. No check is made against the net_device the frame arrived on.
This can cause a frame arriving on any netdev to be delivered to an AF_IUCV socket. Three problems follow.
First, a frame arriving over HiperSockets can be delivered to a socket bound to the classic z/VM IUCV transport, which has iucv->hs_dev == NULL. iucv_sock_bind() takes the classic path whenever the requested userid matches iucv_userid, even on a guest that also has a HiperSockets device carrying the same identifier. The child socket created by afiucv_hs_callback_syn() for such a match inherits hs_dev = NULL and transport = AF_IUCV_TRANS_HIPER, so the first send() on it returns -ENODEV. The socket delivered to accept() is unusable.
Second, a frame arriving on one netdev can be delivered to a socket bound to a different IQD device. Which can lead to
- Accept-queue exhaustion (DoS)
- Attacker-controlled peer identity in the child socket
- Data injection into existing sockets
- Fabric noise on the IQD fabric, where bogus replies are sent
- killing established connections
Third, all AF_IUCV sockets live in init_net, as iucv_sock_alloc() calls sk_alloc(&init_net, ...). But even frames arriving on netdev devices in a namespace can be delivered to an IUCV socket. So a process in an unprivileged user and network namespace holding only the CAP_NET_RAW capability valid within that namespace can send a raw ETH_P_AF_IUCV frame on its own lo device and have it matched against init_net sockets.
Fix all three by skipping any socket whose hs_dev does not match the ingress device. A classic z/VM IUCV socket has hs_dev == NULL; the ingress dev is never NULL, so classic sockets are skipped automatically. An unbound HIPER socket also has hs_dev == NULL and is skipped. A bound HIPER socket is only reachable from the exact IQD device it was bound to. Because hs_dev is always a device in init_net (iucv_sock_bind() scans for_each_netdev_rcu(&init_net, ...) exclusively), a frame whose ingress device belongs to another namespace never matches any socket.
Note that AF_IUCV over HiperSockets provides no per-connection
authentication: no sequence numbers, no TLS, no nonce. The four name fields identifying a connection are exchanged in plaintext on the shared HiperSockets segment (VCHID). Any host on the same HiperSockets segment could spoof any frame type against an existing connection. That is a protocol-level property unchanged by this patch. The fix reduces the attack surface to peers present on the same HiperSockets segment.
--- net/iucv/af_iucv.c | 2 ++ 1 file changed, 2 insertions(+)
net/iucv/af_iucv.c +2 -0
@@ -2073,6 +2073,8 @@ static int afiucv_hs_rcv(struct sk_buff sk =NULL ;read_lock (&iucv_sk_list.lock);sk_for_each (sk, &iucv_sk_list.head) { +if (iucv_sk (sk)->hs_dev != dev) +continue ;if (trans_hdr->flags ==AF_IUCV_FLAG_SYN ) { if ((!memcmp(&iucv_sk(sk)->src_name, trans_hdr->destAppName, 8)) &&
Greg Kroah-Hartman
maintainerPATCH 154/798 xdp: fix zero-copy frame layout
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weiming Shi <[email protected]>
commit 71283aaa6c65b3cec84caf1dc78560985737641f upstream.
xdp_convert_zc_to_xdp_frame() clones an XSK packet into an order-0 page and advertises PAGE_SIZE as its frame size. It allows the copied frame to occupy the page tail needed by skb_shared_info and records zero headroom even when metadata separates the frame header from packet data. An AF_XDP zero-copy packet redirected through cpumap can therefore make the skb overlap skb_shared_info or place it beyond the allocated page.
Limit the copied layout to SKB_WITH_OVERHEAD(PAGE_SIZE) and include the metadata length in frame headroom. Redirect callers already handle a NULL conversion result.
BUG: KASAN: slab-out-of-bounds in skb_gro_receive Write of size 4 at addr ffff88800cf37004 by task cpumap/1/map:1/146 Call Trace: skb_gro_receive (net/core/gro.c:174) udp_gro_receive (net/ipv4/udp_offload.c:812) inet_gro_receive (net/ipv4/af_inet.c:1539) dev_gro_receive (net/core/gro.c:515) gro_receive_skb (net/core/gro.c:633) cpu_map_kthread_run (kernel/bpf/cpumap.c:395) kthread (kernel/kthread.c:436) ret_from_fork (arch/x86/kernel/process.c:164) ret_from_fork_asm (arch/x86/entry/entry_64.S:255) Kernel panic - not syncing: KASAN: panic_on_warn set ...
--- net/core/xdp.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
net/core/xdp.c +2 -2
@@ -456,7 +456,7 @@ struct xdp_frame *xdp_convert_zc_to_xdp_ xdp->data - xdp->data_meta; totsize = xdp->data_end - xdp->data + metasize; -if (sizeof (*xdpf) + totsize >PAGE_SIZE ) +if (sizeof (*xdpf) + totsize >SKB_WITH_OVERHEAD (PAGE_SIZE ))return NULL ; page =dev_alloc_page ();
@@ -473,7 +473,7 @@ struct xdp_frame *xdp_convert_zc_to_xdp_ xdpf->data = addr + metasize; xdpf->len = totsize - metasize; - xdpf->headroom =0 ; + xdpf->headroom = metasize; xdpf->metasize = metasize; xdpf->frame_sz =PAGE_SIZE ; xdpf->mem.type =MEM_TYPE_PAGE_ORDER0 ;
Greg Kroah-Hartman
maintainerPATCH 155/798 slip: fix use-after-free in sl_sync()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Aleksandr Khromov <[email protected]>
commit 2c4e7c42d77e78ad595dbb9e4b5886b58b45d89d upstream.
slip_devs[] stores bare net_device pointers and takes no reference on them. sl_sync() and sl_alloc() walk that table from slip_open() under rtnl_lock(), while an entry is dropped by sl_free_netdev(), which sl_setup() installs as dev->priv_destructor.
priv_destructor is called from netdev_run_todo(), which deliberately runs with the RTNL semaphore released so that it can sleep while waiting for the device refcount to drop:
/* Snapshot list, allow later requests */ list_replace_init(&net_todo_list, &list); __rtnl_unlock(); ... if (dev->priv_destructor) dev->priv_destructor(dev); /* slip_devs[i] = NULL */ if (dev->needs_free_netdev) free_netdev(dev); ... /* Free network device */ kobject_put(&dev->dev.kobj);
So rtnl_lock() does not serialise slip_open() against the teardown at all. sl_sync() can load slip_devs[i] while the entry is still published and dereference it after netdev_run_todo() has run the destructor and released the device:
CPU0 (slip_open) CPU1 (slip_close)
unregister_netdev()
rtnl_unlock()
netdev_run_todo()
__rtnl_unlock()
rtnl_lock()
sl_sync()
dev = slip_devs[i]
priv_destructor(dev)
slip_devs[i] = NULL
kobject_put(&dev->dev.kobj)
/* dev is freed */
sl = netdev_priv(dev)
if (sl->tty || sl->leased) /* use-after-free */BUG: KASAN: use-after-free in sl_sync drivers/net/slip/slip.c:730 [inline] BUG: KASAN: use-after-free in slip_open+0xef4/0x1210 drivers/net/slip/slip.c:806 Read of size 1 at addr ffff8880712dac71 by task syz-executor.2/6506 CPU: 2 PID: 6506 Comm: syz-executor.2 Not tainted 6.1.134-syzkaller-00260-g0c8fc3469765 #0 Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS 1.12.0-1 04/01/2014 Call Trace: sl_sync drivers/net/slip/slip.c:730 [inline] slip_open+0xef4/0x1210 drivers/net/slip/slip.c:806 tty_ldisc_open+0xa2/0x120 drivers/tty/tty_ldisc.c:433 tty_set_ldisc+0x324/0x720 drivers/tty/tty_ldisc.c:564 tiocsetd drivers/tty/tty_io.c:2428 [inline] tty_ioctl+0x5f0/0x1530 drivers/tty/tty_io.c:2712 Allocated by task 6502: alloc_netdev_mqs+0x98/0xfe0 net/core/dev.c:10719 sl_alloc drivers/net/slip/slip.c:756 [inline] slip_open+0x36d/0x1210 drivers/net/slip/slip.c:817 tty_ldisc_open+0xa2/0x120 drivers/tty/tty_ldisc.c:433 tty_set_ldisc+0x324/0x720 drivers/tty/tty_ldisc.c:564 Freed by task 6497: device_release+0xa2/0x240 drivers/base/core.c:2507 kobject_put+0x179/0x280 lib/kobject.c:729 netdev_run_todo+0x6c8/0xef0 net/core/dev.c:10509 slip_close+0x166/0x1c0 drivers/net/slip/slip.c:906 tty_ldisc_close+0x113/0x1a0 drivers/tty/tty_ldisc.c:456 tty_ldisc_kill+0x94/0x160 drivers/tty/tty_ldisc.c:614 tty_ldisc_release+0xe3/0x2b0 drivers/tty/tty_ldisc.c:782 tty_release+0xbcc/0xe70 drivers/tty/tty_io.c:1860
Commit e58c19124189 ("slip: Fix use-after-free Read in slip_open") fixed a different source of stale entries - a device left in slip_devs[] after slip_open() freed it on the registration error path - and does not address this race, which is why the report survives it.
Drop the entry from ndo_uninit instead. unregister_netdevice() calls ndo_uninit under RTNL, before the device is queued to netdev_run_todo(), so an entry that sl_sync() can still see while holding RTNL belongs to a device that cannot be freed until RTNL is dropped. sl_free_netdev() stays only for the slip_open() error path, where register_netdevice() may have failed before ndo_init and ndo_uninit is then not called either. Both running for the same device is harmless: they run under the same RTNL section, so the slot cannot have been reused in between.
This also removes the second symptom of the missing exclusion: a destructor running after sl_alloc() had already handed the slot out to another channel used to clear a live entry, so sl_sync() stopped at that NULL, sl_alloc() returned the same index again, and register_netdevice() failed with -EEXIST because slN was still there.
Reproduced on x86_64 with several threads looping over open("/dev/ptmx") + ioctl(TIOCSETD, N_SLIP) + close().
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- drivers/net/slip/slip.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
drivers/net/slip/slip.c +8 -3
@@ -627,9 +627,15 @@ static void sl_uninit(struct net_devicestruct slip *sl =netdev_priv (dev);sl_free_bufs (sl); +/* Drop the slip_devs[] entry here rather than from the destructor: +* ndo_uninit runs under RTNL, so it cannot race sl_sync(). +*/ + slip_devs[dev->base_addr] =NULL ; } -/* Hook the destructor so we can free slip devices at the right point in time */ +/* Only for the slip_open() error path: register_netdevice() can fail before +* ndo_init, and then ndo_uninit is not called either. +*/ static void sl_free_netdev (struct net_device *dev) {int i = dev->base_addr;
@@ -656,7 +662,6 @@ static void sl_setup(struct net_device * { dev->netdev_ops = &sl_netdev_ops; dev->needs_free_netdev = true; - dev->priv_destructor = sl_free_netdev; dev->hard_header_len =0 ; dev->addr_len =0 ;
@@ -907,7 +912,7 @@ static void slip_close(struct tty_struct#endif /* Flush network side */ unregister_netdev (sl->dev); -/* This will complete via sl_free_netdev */ +/* sl_uninit() has dropped the slip_devs[] entry by now */ }static int slip_hangup (struct tty_struct *tty)
Greg Kroah-Hartman
maintainerPATCH 156/798 net: usb: qmi_wwan: add Telit Cinterion FE990D50 composition
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabio Porcedda <[email protected]>
commit 1056e79fffd0841f43c6a1b25664b196b3caf1c6 upstream.
Add the followin Telit Cinterion FE990D50 composition:
0x0991: rmnet + tty (AT/NMEA) + tty (AT) + tty (AT) + tty (AT) +
tty (diag) + ADPL + adb
T: Bus=01 Lev=01 Prnt=01 Port=06 Cnt=03 Dev#= 10 Spd=480 MxCh= 0 D: Ver= 2.10 Cls=00(>ifc ) Sub=00 Prot=00 MxPS=64 #Cfgs= 1 P: Vendor=1bc7 ProdID=0991 Rev=06.06 S: Manufacturer=Telit Cinterion S: Product=FE990 S: SerialNumber=2aa802d2 C: #Ifs= 9 Cfg#= 1 Atr=e0 MxPwr=500mA I: If#= 0 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=50 Driver=qmi_wwan E: Ad=01(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=81(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=82(I) Atr=03(Int.) MxPS= 8 Ivl=32ms I: If#= 1 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=60 Driver=option E: Ad=02(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=83(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=84(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 2 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=03(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=85(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=86(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 3 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=04(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=87(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=88(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 4 Alt= 0 #EPs= 3 Cls=ff(vend.) Sub=ff Prot=40 Driver=option E: Ad=05(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=89(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8a(I) Atr=03(Int.) MxPS= 10 Ivl=32ms I: If#= 5 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=ff Prot=30 Driver=option E: Ad=06(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8b(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 6 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=80 Driver=(none) E: Ad=8c(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 7 Alt= 0 #EPs= 1 Cls=ff(vend.) Sub=ff Prot=70 Driver=(none) E: Ad=8d(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms I: If#= 8 Alt= 0 #EPs= 2 Cls=ff(vend.) Sub=42 Prot=01 Driver=(none) E: Ad=07(O) Atr=02(Bulk) MxPS= 512 Ivl=0ms E: Ad=8e(I) Atr=02(Bulk) MxPS= 512 Ivl=0ms
--- drivers/net/usb/qmi_wwan.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/usb/qmi_wwan.c +1 -0
@@ -1302,6 +1302,7 @@ static const struct usb_device_id produc {QMI_FIXED_INTF(0x1bbb, 0x0203, 2)}, /* Alcatel L800MA */ {QMI_FIXED_INTF(0x2357, 0x0201, 4)}, /* TP-LINK HSUPA Modem MA180 */ {QMI_FIXED_INTF(0x2357, 0x9000, 4)}, /* TP-LINK MA260 */ + {QMI_QUIRK_SET_DTR(0x1bc7, 0x0991, 0)}, /* Telit FE990D50 */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1031, 3)}, /* Telit LE910C1-EUX */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1034, 2)}, /* Telit LE910C4-WWX */ {QMI_QUIRK_SET_DTR(0x1bc7, 0x1037, 4)}, /* Telit LE910C4-WWX */
Greg Kroah-Hartman
maintainerPATCH 157/798 net: tun: bound receive headroom
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Asim Viladi Oglu Manizada <[email protected]>
commit 447c9303942c439a117d9b76ce6d6e2116b38ee7 upstream.
tun_get_user() uses tun->align both as skb headroom and when choosing how much packet data to keep linear. OVS can propagate an oversized headroom request from another port to TUN or TAP.
When align is larger than the usable space in a one-page skb head, SKB_MAX_HEAD(align) underflows and the result becomes negative when stored in good_linear. That value later wraps when assigned to the size_t linear variable, and tun_alloc_skb() can place skb->data outside the allocated head.
Bound the headroom stored by TUN to the one-page skb-head budget and the largest non-sentinel 16-bit skb header offset. Leave one linear byte for raw TUN and a complete Ethernet header for TAP, including NET_IP_ALIGN.
Also pull the raw-TUN protocol byte and the TAP Ethernet header before accessing them, so these checks remain safe for nonlinear skbs supplied by other allocation paths.
--- drivers/net/tun.c | 21 ++++++++++++++++----- 1 file changed, 16 insertions(+), 5 deletions(-)
drivers/net/tun.c +16 -5
@@ -1169,11 +1169,16 @@ static netdev_features_t tun_net_fix_feastatic void tun_set_headroom (struct net_device *dev,int new_hr) {struct tun_struct *tun =netdev_priv (dev); +size_t max_headroom; -if (new_hr <NET_SKB_PAD ) - new_hr =NET_SKB_PAD ; + max_headroom =min_t (size_t,SKB_MAX_HEAD (0 ),U16_MAX -1 ); - tun->align = new_hr; +if ((tun->flags &TUN_TYPE_MASK ) ==IFF_TAP ) + max_headroom -=ETH_HLEN +NET_IP_ALIGN ; +else + max_headroom -=1 ; + + tun->align =clamp_t (int, new_hr,NET_SKB_PAD , max_headroom); } static void
@@ -1899,7 +1904,13 @@ drop:switch (tun->flags &TUN_TYPE_MASK ) {case IFF_TUN :if (tun->flags &IFF_NO_PI ) { -u8 ip_version = skb->len ? (skb->data[0 ] >>4 ) :0 ; +u8 ip_version; + +if (!pskb_may_pull (skb,1 )) { + err = -EINVAL ; + goto drop; + } + ip_version = skb->data[0 ] >>4 ;switch (ip_version) {case 4 :
@@ -1920,7 +1931,7 @@ drop: skb->dev = tun->dev;break ;case IFF_TAP : -if (frags && !pskb_may_pull (skb,ETH_HLEN )) { +if (!pskb_may_pull (skb,ETH_HLEN )) { err = -ENOMEM ; goto drop; }
Greg Kroah-Hartman
maintainerPATCH 158/798 net: openvswitch: fix flow mask use-after-free on flow deletion
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
commit 4e30317ff67a2eb12b4d890d39f72fd7e7117d48 upstream.
The commit in the Fixes tag below made so flow->mask free is scheduled via RCU right after it is removed from the flow table. The pointer stays in the flow structure and it can be accessible while in the same RCU critical section. This is done to avoid requiring ovs_mutex for the ovs_flow_free().
However, while removing the flow during processing of CMD_DEL, we do not take RCU read lock before the removal, and ovs_flow_cmd_fill_info() uses the flow->mask pointer afterwards. The RCU read lock is taken, but it's already late at that point. The comment on that line acknowledges that the lock is cosmetic and doesn't serve a real purpose.
This leads to use-after-free if the RCU grace period passes between removal and the filling. It is a short race window, but it is there and can lead to a real crash in case memory allocation for the info takes a bit longer:
BUG: KASAN: slab-use-after-free in __ovs_nla_put_key
net/openvswitch/flow_netlink.c:1996
BUG: KASAN: slab-use-after-free in ovs_nla_put_key+0x2463/0x2e30
net/openvswitch/flow_netlink.c:2250
Read of size 4 at addr ffff88801ee89970 by task ovs_flow_del_ec/9487
Call Trace:
<TASK>
__ovs_nla_put_key net/openvswitch/flow_netlink.c:1996
ovs_nla_put_key+0x2463/0x2e30 net/openvswitch/flow_netlink.c:2250
ovs_flow_cmd_fill_info+0x420/0x9c0 net/openvswitch/datapath.c:930
ovs_flow_cmd_del+0x53a/0x970 net/openvswitch/datapath.c:1467
...
netlink_rcv_skb+0x156/0x420 net/netlink/af_netlink.c:2556
</TASK>
Allocated by task 9487:
mask_alloc net/openvswitch/flow_table.c:967
flow_mask_insert net/openvswitch/flow_table.c:1012
ovs_flow_tbl_insert+0xea2/0x1a90 net/openvswitch/flow_table.c:1084
ovs_flow_cmd_new+0x7e3/0xd90 net/openvswitch/datapath.c:1086
...
netlink_rcv_skb+0x156/0x420 net/netlink/af_netlink.c:2556
Freed by task 9485:
rcu_free_sheaf+0x1e/0x100 mm/slub.c:5978
rcu_do_batch kernel/rcu/tree.c:2645
rcu_core+0x59c/0x10c0 kernel/rcu/tree.c:2897
handle_softirqs+0x1e4/0x9a0 kernel/softirq.c:622
...
instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1062ovs_flow_tbl_remove() must be called after the ovs_flow_cmd_fill_info() to avoid this race. This also helps with cleaning up the forced cast and the cosmetic RCU read lock. Before the commit in the Fixes tag the order did not matter as long as the flow object itself was not freed.
A wider RCU critical section could be another option, but we have a GFP_KERNEL allocation in the way.
Reported by Trend Micro's Zero Day Initiative as ZDI-CAN-32042.
--- net/openvswitch/datapath.c | 45 +++++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 22 deletions(-)
net/openvswitch/datapath.c +23 -22
@@ -1404,33 +1404,34 @@ static int ovs_flow_cmd_del(struct sk_bu goto unlock; } -ovs_flow_tbl_remove (&dp->table, flow); -ovs_unlock (); - - reply =ovs_flow_cmd_alloc_info ((const struct sw_flow_actions __force *) flow->sf_acts, + reply =ovs_flow_cmd_alloc_info (ovsl_dereference (flow->sf_acts), &flow->id, info, false, ufid_flags); -if (likely (reply)) { -if (!IS_ERR (reply)) { -rcu_read_lock ();/*To keep RCU checker happy. */ - err =ovs_flow_cmd_fill_info (flow, ovs_header->dp_ifindex, - reply, info->snd_portid, - info->snd_seq,0 , -OVS_FLOW_CMD_DEL , - ufid_flags); -rcu_read_unlock (); -if (WARN_ON_ONCE (err <0 )) { -kfree_skb (reply); - goto out_free; - } +if (IS_ERR (reply)) { +netlink_set_err (sock_net (skb->sk)->genl_sock,0 ,0 , +PTR_ERR (reply)); + reply =NULL ; + } -ovs_notify (&dp_flow_genl_family, reply, info); - }else { -netlink_set_err (sock_net (skb->sk)->genl_sock,0 ,0 , -PTR_ERR (reply)); +if (likely (reply)) { + err =ovs_flow_cmd_fill_info (flow, ovs_header->dp_ifindex, + reply, info->snd_portid, + info->snd_seq,0 , +OVS_FLOW_CMD_DEL , ufid_flags); +if (WARN_ON_ONCE (err <0 )) { +kfree_skb (reply); + reply =NULL ; } } +/* Removal has to happen after ovs_flow_cmd_fill_info(), as it uses +* the flow->mask that can be scheduled to be freed by the +* ovs_flow_tbl_remove() and we're not holding the RCU read lock. +*/ +ovs_flow_tbl_remove (&dp->table, flow); +ovs_unlock (); + +if (likely (reply)) +ovs_notify (&dp_flow_genl_family, reply, info); -out_free:ovs_flow_free (flow, true);return 0 ; unlock:
Greg Kroah-Hartman
maintainerPATCH 159/798 net: openvswitch: fix nf_connlabels leak in ovs_ct_init
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ruoyu Wang <[email protected]>
commit f9de5db270a4c2641de87ee558c16a9bc6eb4cd8 upstream.
ovs_ct_init() acquires a connlabels reference before initializing the conntrack limit state. If ovs_ct_limit_init() fails, its error is returned directly. The pernet core does not invoke the exit callback for the operation whose initialization failed, so ovs_ct_exit() cannot drop the reference.
This leaves labels_used elevated when Open vSwitch pernet registration fails for an existing network namespace. Subsequent conntrack entries in that namespace may allocate label extensions even though Open vSwitch failed to register.
Drop the connlabels reference before returning a conntrack limit initialization error. ovs_ct_limit_init() already releases its partial state, and the original error remains unchanged.
This issue was found by a static analysis checker and confirmed by manual source review.
--- net/openvswitch/conntrack.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-)
net/openvswitch/conntrack.c +5 -3
@@ -2276,6 +2276,7 @@ int ovs_ct_init(struct net *net) {unsigned int n_bits =sizeof (struct ovs_key_ct_labels ) *BITS_PER_BYTE ;struct ovs_net *ovs_net =net_generic (net, ovs_net_id); +int err =0 ;if (nf_connlabels_get (net, n_bits -1 )) { ovs_net->xt_label = false;
@@ -2285,10 +2286,11 @@ int ovs_ct_init(struct net *net) }#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) -return ovs_ct_limit_init (net, ovs_net); -#else -return 0 ; + err =ovs_ct_limit_init (net, ovs_net); +if (err && ovs_net->xt_label) +nf_connlabels_put (net);#endif +return err; }void ovs_ct_exit (struct net *net)
Greg Kroah-Hartman
maintainerPATCH 160/798 NTB: ntb_transport: Recycle TX entries before client callbacks
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 256496397287334a19ed80ec7be92bffcae76b9d upstream.
ntb_tx_copy_callback() invokes the client callback before returning the entry to tx_free_q. The callback may wake a stopped client queue, only for the next enqueue to find no local entry and return -EBUSY. The window is narrow, but the retry is unnecessary.
Save the callback data and length, then return the entry to tx_free_q before invoking the client. A completion callback then means both the client buffer and transport entry are ready for reuse.
--- drivers/ntb/ntb_transport.c | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-)
drivers/ntb/ntb_transport.c +14 -9
@@ -1734,9 +1734,16 @@ static void ntb_transport_rxc_db(unsignestatic void ntb_tx_copy_callback (void *data,const struct dmaengine_result *res) { +struct ntb_payload_header __iomem *hdr;struct ntb_queue_entry *entry = data; -struct ntb_transport_qp *qp = entry->qp; -struct ntb_payload_header __iomem *hdr = entry->tx_hdr; +struct ntb_transport_qp *qp; +unsigned int len; +void *cb_data; + + qp = entry->qp; + hdr = entry->tx_hdr; + cb_data = entry->cb_data; + len = entry->len;/* we need to check DMA results if we are using DMA */ if (res) {
@@ -1776,15 +1783,13 @@ static void ntb_tx_copy_callback(void *d* "link down" or similar. Since no payload is being sent in these * cases, there is nothing to add to the completion queue. */ -if (entry->len >0 ) { - qp->tx_bytes += entry->len; - -if (qp->tx_handler) - qp->tx_handler (qp, qp->cb_data, entry->cb_data, - entry->len); - } +if (len >0 ) + qp->tx_bytes += len;ntb_list_add (&qp->ntb_tx_free_q_lock, &entry->entry, &qp->tx_free_q); + +if (len >0 && qp->tx_handler) + qp->tx_handler (qp, qp->cb_data, cb_data, len); }static void ntb_memcpy_tx (struct ntb_queue_entry *entry,void __iomem *offset)
Greg Kroah-Hartman
maintainerPATCH 161/798 NTB: ntb_transport: Fail TX enqueue when the QP link is down
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 873ce713fef5dde0939220f04f3484ec86a16fba upstream.
Commit f195a1a6fe41 ("ntb: Drop packets when qp link is down") meant to make ntb_transport_tx_enqueue() drop packets submitted while the QP link is down, but it only returns 0 without consuming the packet. Zero means success by this function's contract, so ntb_netdev reports NETDEV_TX_OK and forgets the skb: nothing queued it, nothing frees it, and it leaks, one skb for every transmit racing a link-down.
Return -ENOLINK instead, restoring the contract that a non-zero return leaves the buffer owned by the caller. With the preceding patch, ntb_netdev frees the skb on non-retryable enqueue failures and returns NETDEV_TX_OK, so a packet racing with link-down is dropped without leaking or entering a busy retry loop.
--- drivers/ntb/ntb_transport.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/ntb/ntb_transport.c +1 -2
@@ -2293,9 +2293,8 @@ int ntb_transport_tx_enqueue(struct ntb_if (!qp || !len)return -EINVAL ; -/* If the qp link is down already, just ignore. */ if (!qp->link_is_up) -return 0 ; +return -ENOLINK ; entry =ntb_list_rm (&qp->ntb_tx_free_q_lock, &qp->tx_free_q);if (!entry) {
Greg Kroah-Hartman
maintainerPATCH 162/798 NTB: ntb_transport: Reject oversized TX buffers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit a4f2387db6f1cc2f03abba7f3a6807ad61e26ff7 upstream.
ntb_process_tx() handles an oversized buffer by calling tx_handler() with a NULL data pointer and returning success. ntb_netdev therefore neither frees the skb in its completion callback nor takes its enqueue error path, leaking it.
Reject oversized buffers in ntb_transport_tx_enqueue() before acquiring a queue entry and return -EMSGSIZE. The caller retains ownership of the buffer, and the preceding netdev patch frees the skb when enqueue returns this permanent error.
--- drivers/ntb/ntb_transport.c | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-)
drivers/ntb/ntb_transport.c +3 -9
@@ -1913,15 +1913,6 @@ static int ntb_process_tx(struct ntb_trareturn -EAGAIN ; } -if (entry->len > qp->tx_max_frame -sizeof (struct ntb_payload_header )) { -if (qp->tx_handler) - qp->tx_handler (qp, qp->cb_data,NULL , -EIO ); - -ntb_list_add (&qp->ntb_tx_free_q_lock, &entry->entry, - &qp->tx_free_q); -return 0 ; - } -ntb_async_tx (qp, entry); qp->tx_index++;
@@ -2296,6 +2287,9 @@ int ntb_transport_tx_enqueue(struct ntb_if (!qp->link_is_up)return -ENOLINK ; +if (len > qp->tx_max_frame -sizeof (struct ntb_payload_header )) +return -EMSGSIZE ; + entry =ntb_list_rm (&qp->ntb_tx_free_q_lock, &qp->tx_free_q);if (!entry) { qp->tx_err_no_buf++;
Greg Kroah-Hartman
maintainerPATCH 163/798 net: ntb_netdev: Avoid double-accounting netif_rx() drops
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 82e15be2d8b9efa6fb1750528d9b6f40e6a8eea7 upstream.
netif_rx() already accounts packets it drops in the core rx_dropped counter. ntb_netdev counts them again as both errors and drops.
Leave netif_rx() drops to the core. Count the packet and bytes unconditionally since it was received successfully by the driver.
--- drivers/net/ntb_netdev.c | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-)
drivers/net/ntb_netdev.c +3 -7
@@ -125,13 +125,9 @@ static void ntb_netdev_rx_handler(struct skb->protocol =eth_type_trans (skb, ndev); skb->ip_summed =CHECKSUM_NONE ; -if (netif_rx (skb) ==NET_RX_DROP ) { - ndev->stats.rx_errors++; - ndev->stats.rx_dropped++; - }else { - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += len; - } +netif_rx (skb); + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; skb = new_skb;
Greg Kroah-Hartman
maintainerPATCH 164/798 net: ntb_netdev: Count packets dropped on RX refill failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 31ded341c375bb2faac1d77ab0012a732ba3e2a6 upstream.
When replacement skb allocation fails, ntb_netdev drops a packet that was received successfully and requeues the original buffer. The drop is counted, but rx_packets and rx_bytes are not.
Count every good packet before allocating its replacement.
--- drivers/net/ntb_netdev.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/net/ntb_netdev.c +3 -2
@@ -115,6 +115,9 @@ static void ntb_netdev_rx_handler(struct goto enqueue_again; } + ndev->stats.rx_packets++; + ndev->stats.rx_bytes += len; + new_skb =netdev_alloc_skb (ndev, ndev->mtu +ETH_HLEN );if (!new_skb) { ndev->stats.rx_dropped++;
@@ -126,8 +129,6 @@ static void ntb_netdev_rx_handler(struct skb->ip_summed =CHECKSUM_NONE ;netif_rx (skb); - ndev->stats.rx_packets++; - ndev->stats.rx_bytes += len; skb = new_skb;
Greg Kroah-Hartman
maintainerPATCH 165/798 net: cap advertised IP tunnel headroom
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit 6b222adeb9340306e2ff97127c76117abb9b3df8 upstream.
IP tunnel devices derive their advertised needed_headroom from lower output devices. A stack of user-created devices can make the derived value larger than the 16-bit skb header offsets can represent. Once IP output reserves it, skb head expansion can wrap those offsets.
The runtime transmit path already caps a growing needed_headroom at 512. Apply the same cap when tunnel configuration publishes needed_headroom derived from a lower output device.
Capping the advertised value is safe: IP tunnel transmit still expands the skb when a packet needs more headroom. A nonsensical stacked configuration can therefore incur an extra reallocation, but it cannot publish an unbounded reservation to upper layers.
--- include/net/ip_tunnels.h | 11 +++++++++-- net/ipv4/ip_tunnel.c | 2 +- net/ipv6/ip6_gre.c | 7 +++++-- net/ipv6/ip6_tunnel.c | 7 +++++-- net/ipv6/sit.c | 2 +- 5 files changed, 21 insertions(+), 8 deletions(-)
include/net/ip_tunnels.h +9 -2
@@ -471,8 +471,7 @@ struct metadata_dst *iptunnel_metadata_rint skb_tunnel_check_pmtu (struct sk_buff *skb,struct dst_entry *encap_dst,int headroom,bool reply); -static inline void ip_tunnel_adj_headroom (struct net_device *dev, -unsigned int headroom) +static inline unsigned int ip_tunnel_limit_headroom (unsigned int headroom) {/* we must cap headroom to some upperlimit, else pskb_expand_head * will overflow header offsets in skb_headers_offset_update().
@@ -482,6 +481,14 @@ static inline void ip_tunnel_adj_headrooif (headroom > max_allowed) headroom = max_allowed; +return headroom; +} + +static inline void ip_tunnel_adj_headroom (struct net_device *dev, +unsigned int headroom) +{ + headroom =ip_tunnel_limit_headroom (headroom); +if (headroom >READ_ONCE (dev->needed_headroom))WRITE_ONCE (dev->needed_headroom, headroom); }
net/ipv4/ip_tunnel.c +1 -1
@@ -316,7 +316,7 @@ static int ip_tunnel_bind_dev(struct net mtu =min (tdev->mtu,IP_MAX_MTU ); } - dev->needed_headroom = t_hlen + hlen; + dev->needed_headroom =ip_tunnel_limit_headroom (t_hlen + hlen); mtu -= t_hlen + (dev->type ==ARPHRD_ETHER ? dev->hard_header_len :0 );if (mtu <IPV4_MIN_MTU )
net/ipv6/ip6_gre.c +5 -2
@@ -1151,8 +1151,11 @@ static void ip6gre_tnl_link_config_routereturn ;if (rt->dst.dev) { - dev->needed_headroom = rt->dst.dev->hard_header_len + - t_hlen; +unsigned int headroom; + + headroom = rt->dst.dev->hard_header_len + t_hlen; + headroom =ip_tunnel_limit_headroom (headroom); + dev->needed_headroom = headroom;if (set_mtu) {int mtu = rt->dst.dev->mtu - t_hlen;
net/ipv6/ip6_tunnel.c +5 -2
@@ -1527,8 +1527,11 @@ static void ip6_tnl_link_config(struct i tdev =__dev_get_by_index (t->net, p->link);if (tdev) { - dev->needed_headroom = tdev->hard_header_len + - tdev->needed_headroom + t_hlen; +unsigned int headroom; + + headroom = tdev->hard_header_len + tdev->needed_headroom; + headroom += t_hlen; + dev->needed_headroom =ip_tunnel_limit_headroom (headroom); mtu = min_t(unsigned int, tdev->mtu, IP6_MAX_MTU); mtu = mtu - t_hlen;
net/ipv6/sit.c +1 -1
@@ -1132,7 +1132,7 @@ static void ipip6_tunnel_bind_dev(structWRITE_ONCE (dev->mtu, mtu); hlen = tdev->hard_header_len + tdev->needed_headroom; } - dev->needed_headroom = t_hlen + hlen; + dev->needed_headroom =ip_tunnel_limit_headroom (t_hlen + hlen); } static void ipip6_tunnel_update(struct ip_tunnel *t, struct ip_tunnel_parm *p,
Greg Kroah-Hartman
maintainerPATCH 166/798 seg6: reset IP6CB after IPv6 decapsulation
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit f967455fb2a5a2079b9eb5823e9ccf359174bf9f upstream.
decap_and_validate() pulls the outer SRv6 headers and makes the inner packet the skb network header. The IPv6 control block still contains values collected while parsing the outer packet, including nhoff and extension-header flags.
End.DX6 and End.DT6 route the inner IPv6 packet directly to the IPv6 input path. An unprivileged user can reach End.DT6 from a user and net namespace by installing a local SID and injecting an outer packet with Hop-by-Hop and Destination Options headers followed by an SRH and a minimal inner IPv6 packet.
The outer extension headers leave a large nhoff in IP6CB. After decapsulation, ip6_protocol_deliver_rcu() uses that stale offset on the inner packet and reads beyond the skb head. KASAN reports:
BUG: KASAN: slab-out-of-bounds in ip6_protocol_deliver_rcu ip6_protocol_deliver_rcu+0x1118/0x1450 ip6_input_finish+0x11b/0x240 seg6_local_input_core+0xed/0x2e0 lwtunnel_input+0x1e9/0x4e0 ipv6_rthdr_rcv+0x525f/0x6c50 ip6_protocol_deliver_rcu+0xcb7/0x1450
Before clearing IP6CB for an inner IPv6 packet, save its incoming interface index and L3 slave state. Restore both after the clear and set nhoff to the inner IPv6 base-header nexthdr field.
Use IP6CB(skb)->iif rather than skb->skb_iif because VRF processing can replace skb_iif with the L3 master while IP6CB keeps the receiving interface. Preserve IP6SKB_L3SLAVE for the same reason.
--- net/ipv6/seg6_local.c | 9 +++++++++ 1 file changed, 9 insertions(+)
net/ipv6/seg6_local.c +9 -0
@@ -144,6 +144,15 @@ static bool decap_and_validate(struct skmemset (IPCB (skb),0 ,sizeof (*IPCB (skb)));IPCB (skb)->iif = iif; + }else if (proto ==IPPROTO_IPV6 ) { +bool l3slave =ipv6_l3mdev_skb (IP6CB (skb)->flags); +int iif =IP6CB (skb)->iif; + +memset (IP6CB (skb),0 ,sizeof (*IP6CB (skb))); +IP6CB (skb)->iif = iif; +IP6CB (skb)->nhoff = offsetof(struct ipv6hdr , nexthdr); +if (l3slave) +IP6CB (skb)->flags |=IP6SKB_L3SLAVE ; }return true;
Greg Kroah-Hartman
maintainerPATCH 167/798 ALSA: 6fire: bound the MIDI event length from the device
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit a478893b59e36cfe7d77a76b352f2db55502e879 upstream.
usb6fire_comm_receiver_handler() forwards a MIDI event using a length byte the device supplies, with no bound and no check that the transfer delivered that many bytes:
if (!urb->status) {
if (rt->receiver_buffer[0] == 0x10) /* midi in event */
if (midi_rt)
midi_rt->in_received(midi_rt,
rt->receiver_buffer + 2,
rt->receiver_buffer[1]);
}receiver_buffer is a 64-byte kzalloc() buffer (COMM_RECEIVER_BUFSIZE), so only 62 bytes follow the two-byte header. receiver_buffer[1] is a u8 the device chooses, so a device that answers with 0x10 and a length of 0xFF makes snd_rawmidi_receive() read 255 bytes starting two bytes into a 64-byte object. The bytes past the buffer are handed to userspace through the rawmidi read path.
urb->actual_length is not consulted either, so a short transfer leaves both the type byte and the length byte at their previous values and the handler acts on stale data.
The receiver URB is submitted from usb6fire_comm_init() at probe, so the read happens on plug with no user action; forwarding to userspace also needs a MIDI input substream open, since usb6fire_midi_in_received() only calls snd_rawmidi_receive() when rt->in is set.
KASAN on 7.2.0-rc5 (arm64), single packet from an emulated device:
BUG: KASAN: slab-out-of-bounds in snd_rawmidi_receive Read of size 255 at addr ffff000009f64682 by task bash/183 __asan_memcpy snd_rawmidi_receive usb6fire_midi_in_received [snd_usb_6fire] usb6fire_comm_receiver_handler [snd_usb_6fire] Allocated by task 11: usb6fire_comm_init [snd_usb_6fire] usb6fire_chip_probe [snd_usb_6fire] The buggy address is located 2 bytes inside of allocated 64-byte region [ffff000009f64680, ffff000009f646c0)
Reject the event when the length exceeds the bytes that follow the header, and require the transfer to have delivered the header plus that many bytes. The receiver URB is submitted with a 64-byte transfer_buffer_length, so a genuine device cannot deliver an event longer than those 62 bytes and nothing valid is dropped.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/6fire/comm.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-)
sound/usb/6fire/comm.c +6 -3
@@ -36,11 +36,14 @@ static void usb6fire_comm_receiver_handlstruct midi_runtime *midi_rt = rt->chip->midi;if (!urb->status) { -if (rt->receiver_buffer[0 ] ==0x10 )/* midi in event */ +u8 len = rt->receiver_buffer[1 ]; + +if (rt->receiver_buffer[0 ] ==0x10 &&/* midi in event */ + len <=COMM_RECEIVER_BUFSIZE -2 && + urb->actual_length >= len +2 )if (midi_rt) midi_rt->in_received (midi_rt, - rt->receiver_buffer +2 , - rt->receiver_buffer[1 ]); + rt->receiver_buffer +2 , len); }if (!rt->chip->shutdown) {
Greg Kroah-Hartman
maintainerPATCH 168/798 ALSA: bcd2000: clear the URB pointers on disconnect
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Baul Lee <[email protected]>
commit 459d3a64766f5ca2f1886daeaf24582831a5f5ab upstream.
bcd2000_free_usb_related_resources() frees both URBs and leaves the pointers behind:
usb_kill_urb(bcd2k->midi_out_urb); usb_kill_urb(bcd2k->midi_in_urb); usb_free_urb(bcd2k->midi_out_urb); usb_free_urb(bcd2k->midi_in_urb);
The rawmidi device outlives that call. A substream that is still open when the device is unplugged reaches bcd2000_midi_send() from the trigger path on close. That function writes to the freed URB and then hands it to the USB core:
bcd2k->midi_out_urb->transfer_buffer_length = BUFSIZE; ... ret = usb_submit_urb(bcd2k->midi_out_urb, GFP_ATOMIC);
usb_kill_urb() does not stop a later submission either, so a submit that races the disconnect can requeue the URB after it has been reaped. midi_in_urb is exposed the same way: bcd2000_input_complete() resubmits it from the completion handler.
KASAN on 7.2.0-rc5 (arm64):
BUG: KASAN: slab-use-after-free in bcd2000_midi_send [snd_bcd2000] Write of size 4 at addr ffff00001827d388 by task bpoc/168 __asan_store4 bcd2000_midi_send [snd_bcd2000] bcd2000_midi_output_trigger [snd_bcd2000] snd_rawmidi_kernel_write1 close_substream.part.0 Freed by task 168: usb_free_urb bcd2000_disconnect [snd_bcd2000] BUG: KASAN: slab-use-after-free in usb_submit_urb Read of size 8 at addr ffff00001827d3b8 by task bpoc/168
Clear both pointers after freeing and test them on the paths that can still run. Poison the URBs before freeing them: usb_poison_urb() waits for a running completion handler and rejects any later submission, so after it returns the input path is quiesced and only the rawmidi trigger path can still reach bcd2000_midi_send(). No unpoison is needed; the URBs are freed on the next line.
Discovered by XBOW, triaged by Baul Lee <[email protected]>
--- sound/usb/bcd2000/bcd2000.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-)
sound/usb/bcd2000/bcd2000.c +8 -3
@@ -134,6 +134,9 @@ static void bcd2000_midi_send(struct bcdif (!midi_out_substream)return ; +if (!bcd2k->midi_out_urb) +return ; +/* copy command prefix bytes */ memcpy (bcd2k->midi_out_buf, device_cmd_prefix,sizeof (device_cmd_prefix));
@@ -178,7 +181,7 @@ static int bcd2000_midi_output_close(str {struct bcd2000 *bcd2k = substream->rmidi->private_data; -if (bcd2k->midi_out_active) { +if (bcd2k->midi_out_active && bcd2k->midi_out_urb) {usb_kill_urb (bcd2k->midi_out_urb); bcd2k->midi_out_active =0 ; }
@@ -348,11 +351,13 @@ static int bcd2000_init_midi(struct bcd2static void bcd2000_free_usb_related_resources (struct bcd2000 *bcd2k,struct usb_interface *interface) { -usb_kill_urb (bcd2k->midi_out_urb); -usb_kill_urb (bcd2k->midi_in_urb); +usb_poison_urb (bcd2k->midi_out_urb); +usb_poison_urb (bcd2k->midi_in_urb);usb_free_urb (bcd2k->midi_out_urb);usb_free_urb (bcd2k->midi_in_urb); + bcd2k->midi_out_urb =NULL ; + bcd2k->midi_in_urb =NULL ;if (bcd2k->intf) {usb_set_intfdata (bcd2k->intf,NULL );
Greg Kroah-Hartman
maintainerPATCH 169/798 ALSA: mpu401: Check card index validity at probe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit f7dcecb92ed192ff5fcf842918fb1aaea84b5bdd upstream.
mpu401 driver blindly trusts that the given devptr->id value is within the proper card index range at probe. It's OK for the devices the driver itself creates at the module probe time, but if the device is bound manually via sysfs interface, this could be -1 as "none", and this leads to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/mpu401/mpu401.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/mpu401/mpu401.c +6 -0
@@ -93,6 +93,12 @@ static int snd_mpu401_probe(struct platfint err;struct snd_card *card; +if (dev <0 || dev >=SNDRV_CARDS ) { +dev_warn (&devptr->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +if (port[dev] ==SNDRV_AUTO_PORT ) {snd_printk (KERN_ERR "specify port\n" );return -EINVAL ;
Greg Kroah-Hartman
maintainerPATCH 170/798 ALSA: mts64: Check card index validity at probe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit d18a260720f86a5f8b5fcfefc4ba2e9dd01c10f8 upstream.
Although mts64 driver has a check of the given devptr->id value, it doesn't check for a negative id, which is often given as "none" or such value when bound via sysfs. This may lead to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/mts64.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/mts64.c +6 -0
@@ -920,6 +920,12 @@ static int snd_mts64_probe(struct platfo p =platform_get_drvdata (pdev);platform_set_drvdata (pdev,NULL ); +if (dev <0 ) { +dev_warn (&pdev->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +if (dev >=SNDRV_CARDS )return -ENODEV ;if (!enable[dev])
Greg Kroah-Hartman
maintainerPATCH 171/798 ALSA: portman2x4: Check card index validity at probe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit 3690ef20469d5959378260e2752f2314a2572913 upstream.
Although portman2x4 driver has a check of the given devptr->id value, it doesn't check for a negative id, which is often given as "none" or such value when bound via sysfs. This may lead to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/portman2x4.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/portman2x4.c +6 -0
@@ -716,6 +716,12 @@ static int snd_portman_probe(struct plat p =platform_get_drvdata (pdev);platform_set_drvdata (pdev,NULL ); +if (dev <0 ) { +dev_warn (&pdev->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +if (dev >=SNDRV_CARDS )return -ENODEV ;if (!enable[dev])
Greg Kroah-Hartman
maintainerPATCH 172/798 ALSA: serial-u16550: Check card index validity at probe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit e0fb960b227fcdebe22e4f26c9486d60943c0424 upstream.
serial-u16550 driver blindly trusts that the given devptr->id value is within the proper card index range at probe. It's OK for the devices the driver itself creates at the module probe time, but if the device is bound manually via sysfs interface, this could be -1 as "none", and this leads to OOB access for index[] and other parameters.
Add a sanity check for the card index and warn/correct it if it's a value out of the range.
--- sound/drivers/serial-u16550.c | 6 ++++++ 1 file changed, 6 insertions(+)
sound/drivers/serial-u16550.c +6 -0
@@ -889,6 +889,12 @@ static int snd_serial_probe(struct platfint err;int dev = devptr->id; +if (dev <0 || dev >=SNDRV_CARDS ) { +dev_warn (&devptr->dev, +"Invalid card index %d, using default 0\n" , dev); + dev =0 ; + } +switch (adaptor[dev]) {case SNDRV_SERIAL_SOUNDCANVAS : ins[dev] =1 ;
Greg Kroah-Hartman
maintainerPATCH 173/798 netfilter: nf_queue: pin bridge device while NFQUEUE holds fake dst
In reply to Greg Kroah-Hartman5.10-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 | 16 ++++++++++++++++ net/netfilter/nfnetlink_queue.c | 3 +++ 3 files changed, 20 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 +16 -0
@@ -67,6 +67,7 @@ static void nf_queue_entry_release_refs(struct nf_queue_entry *entry)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_physdevs(struct nf_queue_entry *entry) {#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 ;struct nf_bridge_info *nf_bridge; nf_bridge =nf_bridge_info_get (skb);
@@ -93,6 +96,18 @@ static void __nf_queue_entry_init_physdevs(struct nf_queue_entry *entry) entry->physin =NULL ; entry->physout = NULL; } + +if (entry->state.pf ==NFPROTO_BRIDGE && + dst && (dst->flags &DST_FAKE_RTABLE )) { +WARN_ON_ONCE (!rcu_read_lock_held ()); + dev =READ_ONCE (dst->dev); + } + +/* 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 }
@@ -109,6 +124,7 @@ bool nf_queue_entry_get_refs(struct nf_queue_entry *entry)dev_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
@@ -910,6 +910,9 @@ dev_cmp(struct nf_queue_entry *entry, unsigned long ifindex)if (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 ;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 174/798 mptcp: pm: ADD_ADDR rtx: always decrease sk refcount
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit 9634cb35af17019baec21ca648516ce376fa10e6 ]
When an ADD_ADDR is retransmitted, the sk is held in sk_reset_timer(). It should then be released in all cases at the end.
Some (unlikely) checks were returning directly instead of calling sock_put() to decrease the refcount. Jump to a new 'exit' label to call __sock_put() (which will become sock_put() in the next commit) to fix this potential leak.
While at it, drop the '!msk' check which cannot happen because it is never reset, and explicitly mark the remaining one as "unlikely".
[ Karl Mehltretter: applied to pm_netlink.c; retained v5.10's ID 0 guard
and routed it through the common refcount drop. ]
--- net/mptcp/pm_netlink.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
net/mptcp/pm_netlink.c +4 -6
@@ -217,14 +217,11 @@ static void mptcp_pm_add_timer(struct timer_list *timer)pr_debug ("msk=%p\n" , msk); -if (!msk) -return ; - -if (inet_sk_state_load (sk) ==TCP_CLOSE ) -return ; +if (unlikely (inet_sk_state_load (sk) ==TCP_CLOSE )) + goto exit;if (!entry->addr.id) -return ; + goto exit;bh_lock_sock (sk);if (sock_owned_by_user (sk)) {
@@ -253,6 +250,7 @@ static void mptcp_pm_add_timer(struct timer_list *timer) out:bh_unlock_sock (sk); +exit:__sock_put (sk); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 175/798 mptcp: pm: ADD_ADDR rtx: free sk if last
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthieu Baerts (NGI0) <[email protected]>
[ Upstream commit b7b9a461569734d33d3259d58d2507adfac107ed ]
When an ADD_ADDR is retransmitted, the sk is held in sk_reset_timer(), and released at the end.
If at that moment, it was the last reference being held, the sk would not be freed. sock_put() should then be called instead of __sock_put().
But that's not enough: if it is the last reference, sock_put() will call sk_free(), which will end up calling sk_stop_timer_sync() on the same timer, and waiting indefinitely to finish. So it is needed to mark that the timer is done at the end of the timer handler when it has not been rescheduled, not to call sk_stop_timer_sync() on "itself".
[ Karl Mehltretter: applied to pm_netlink.c and retained v5.10's fixed
retransmission delays while centralizing timer rearming. ]
--- net/mptcp/pm_netlink.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-)
net/mptcp/pm_netlink.c +17 -9
@@ -34,6 +34,7 @@ struct mptcp_pm_add_entry {struct timer_list add_timer;struct mptcp_sock *sock;u8 retrans_times; +bool timer_done;struct rcu_head rcu; };
@@ -214,24 +215,25 @@ static void mptcp_pm_add_timer(struct timer_list *timer)struct mptcp_pm_add_entry *entry =from_timer (entry, timer, add_timer);struct mptcp_sock *msk = entry->sock;struct sock *sk = (struct sock *)msk; +unsigned int timeout =0 ;pr_debug ("msk=%p\n" , msk); +bh_lock_sock (sk);if (unlikely (inet_sk_state_load (sk) ==TCP_CLOSE )) - goto exit; + goto out;if (!entry->addr.id) - goto exit; + goto out; -bh_lock_sock (sk);if (sock_owned_by_user (sk)) {/* Try again later. */ -sk_reset_timer (sk, timer, jiffies +HZ /20 ); + timeout =HZ /20 ; goto out; }if (mptcp_pm_should_add_signal (msk)) { -sk_reset_timer (sk, timer, jiffies +TCP_RTO_MAX /8 ); + timeout =TCP_RTO_MAX /8 ; goto out; }
@@ -244,14 +246,18 @@ static void mptcp_pm_add_timer(struct timer_list *timer) }if (entry->retrans_times <ADD_ADDR_RETRANS_MAX ) -sk_reset_timer (sk, timer, jiffies +TCP_RTO_MAX ); + timeout =TCP_RTO_MAX ;spin_unlock_bh (&msk->pm.lock); out: +if (timeout) +sk_reset_timer (sk, timer, jiffies + timeout); +else +/* if sock_put calls sk_free: avoid waiting for this timer */ + entry->timer_done = true;bh_unlock_sock (sk); -exit: -__sock_put (sk); +sock_put (sk); } struct mptcp_pm_add_entry *
@@ -304,6 +310,7 @@ static bool mptcp_pm_alloc_anno_list(struct mptcp_sock *msk, add_entry->retrans_times =0 ;timer_setup (&add_entry->add_timer, mptcp_pm_add_timer,0 ); + add_entry->timer_done = false;sk_reset_timer (sk, &add_entry->add_timer, jiffies +TCP_RTO_MAX );return true;
@@ -322,7 +329,8 @@ void mptcp_pm_free_anno_list(struct mptcp_sock *msk)spin_unlock_bh (&msk->pm.lock);list_for_each_entry_safe (entry, tmp, &free_list, list) { -sk_stop_timer_sync (sk, &entry->add_timer); +if (!entry->timer_done) +sk_stop_timer_sync (sk, &entry->add_timer);kfree_rcu (entry, rcu); } }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 176/798 PCI: hv: Set irq_retrigger callback for the Hyper-V PCI MSI irqchip
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Naman Jain <[email protected]>
[ Upstream commit 86bdd16e8f390d51bae9e77a4bc4164ca2f580fe ]
The Hyper-V vPCI MSI irqchip never installs an irq_retrigger() callback.
On CPU hot-unplug fixup_irqs() migrates the interrupts which are affine to the outgoing CPU to a new target. If an interrupt still has its pending bit set in the outgoing CPU's IRR at that point, fixup_irqs() resends it on the new target through the irqchip's irq_retrigger() callback. As the Hyper-V PCI/MSI chip does not provide that callback, the pending interrupt is silently dropped, which can result in lost interrupts, stalls and "No irq handler for vector" messages during CPU hotplug.
Install irq_chip_retrigger_hierarchy() as the irq_retrigger() callback for the Hyper-V PCI/MSI irqchip, so that a pending interrupt is resent on its new target CPU via the parent x86 vector domain.
--- drivers/pci/controller/pci-hyperv.c | 1 + 1 file changed, 1 insertion(+)
drivers/pci/controller/pci-hyperv.c +1 -0
@@ -1595,6 +1595,7 @@ static struct irq_chip hv_msi_irq_chip = .irq_compose_msi_msg = hv_compose_msi_msg, .irq_set_affinity = hv_set_affinity, .irq_ack = irq_chip_ack_parent, + .irq_retrigger = irq_chip_retrigger_hierarchy, .irq_mask = hv_irq_mask, .irq_unmask = hv_irq_unmask, };
Greg Kroah-Hartman
maintainerPATCH 177/798 dm-stats: fix a crash if allocation of per-cpu data fails
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit cc87e26d9cce22061dc21e51e11afef29dbbc36a upstream.
If "dm_kvzalloc(percpu_alloc_size, cpu_to_node(cpu))" fails, the code jumps to the "out" label and calls dm_stat_free. dm_stat_free does "for_each_possible_cpu(cpu) { dm_kvfree(s->stat_percpu[cpu][0].histogram, s->histogram_alloc_size);", which crashes with NULL pointer dereference if s->stat_percpu[cpu] is NULL.
This commit fixes the bug by testing s->stat_percpu[cpu] for NULL before using it.
--- drivers/md/dm-stats.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/md/dm-stats.c +4 -2
@@ -175,8 +175,10 @@ static void dm_stat_free(struct rcu_headkfree (s->program_id);kfree (s->aux_data);for_each_possible_cpu (cpu) { -dm_kvfree (s->stat_percpu[cpu][0 ].histogram, s->histogram_alloc_size); -dm_kvfree (s->stat_percpu[cpu], s->percpu_alloc_size); +if (s->stat_percpu[cpu]) { +dm_kvfree (s->stat_percpu[cpu][0 ].histogram, s->histogram_alloc_size); +dm_kvfree (s->stat_percpu[cpu], s->percpu_alloc_size); + } }dm_kvfree (s->stat_shared[0 ].tmp.histogram, s->histogram_alloc_size);dm_kvfree (s, s->shared_alloc_size);
Greg Kroah-Hartman
maintainerPATCH 178/798 dm-switch: use WRITE_ONCE() in switch_region_table_write()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haotian Zhang <[email protected]>
commit c7391ebe33162c7962b313caea4d8e6b0bc2a671 upstream.
switch_region_table_read() accesses the region table with READ_ONCE() and is called from the lockless switch_map() IO path. However, switch_region_table_write() stores to the same array with a plain assignment. This results in an inconsistent access pattern for a lockless shared variable and may trigger data race reports.
Use WRITE_ONCE() to pair with the existing READ_ONCE() in switch_region_table_read().
--- drivers/md/dm-switch.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/md/dm-switch.c +1 -1
@@ -183,7 +183,7 @@ static void switch_region_table_write(st pte = sctx->region_table[region_index]; pte &= ~((((region_table_slot_t )1 << sctx->region_table_entry_bits) -1 ) << bit); pte |= (region_table_slot_t )value << bit; - sctx->region_table[region_index] = pte; +WRITE_ONCE (sctx->region_table[region_index], pte); }/*
Greg Kroah-Hartman
maintainerPATCH 179/798 i3c: master: Fix info leak and UAF in device unregister path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adrian Hunter <[email protected]>
commit d2c743efd2d1ee64e94324664808f623dd865872 upstream.
i3c_master_unregister_i3c_devs() clears i3cdev->dev->desc before calling device_unregister(). During device_unregister(), device_del() emits a KOBJ_REMOVE uevent and unbinds the driver while the device descriptor is still expected to be valid. As a result, i3c_device_uevent() and a racing modalias_show() can observe a NULL desc and fall back to an uninitialized stack struct i3c_device_info, leaking kernel stack contents in the generated modalias. Driver .remove() callbacks may also encounter an unexpected NULL desc during unbind.
Keep desc valid until device_unregister() has completed. Since device_unregister() drops the device reference and may free the device, take an extra reference with get_device() before unregistering. Clear desc afterwards and release the extra reference with put_device(). This preserves the release-time invariant that desc must be NULL while avoiding both the information leak and a potential use-after-free from writing desc after the device has been released.
--- drivers/i3c/master.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/i3c/master.c +5 -4
@@ -2279,11 +2279,12 @@ static void i3c_master_unregister_i3c_deif (!i3cdev->dev)continue ; - i3cdev->dev->desc =NULL ; -if (device_is_registered (&i3cdev->dev->dev)) +if (device_is_registered (&i3cdev->dev->dev)) { +get_device (&i3cdev->dev->dev);device_unregister (&i3cdev->dev->dev); -else -put_device (&i3cdev->dev->dev); + } + i3cdev->dev->desc =NULL ; +put_device (&i3cdev->dev->dev); i3cdev->dev =NULL ; } }
Greg Kroah-Hartman
maintainerPATCH 180/798 wifi: brcmfmac: Fix memory leak in brcmf_sdio_read_control()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 0d10db8e94fcb23a799789aaa696b4d8f937e207 upstream.
The memory allocated for buf is not freed in some of the error paths in brcmf_sdio_read_control(). Fix that by adding vfree() calls.
--- drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c +2 -1
@@ -1815,17 +1815,18 @@ gotpkt:if (bus->rxctl) {brcmf_err ("last control frame is being processed.\n" );spin_unlock_bh (&bus->rxctl_lock); -vfree (buf); goto done; } bus->rxctl = buf + doff; bus->rxctl_orig = buf; bus->rxlen = len - doff;spin_unlock_bh (&bus->rxctl_lock); + buf =NULL ; done:/* Awake any waiters */ brcmf_sdio_dcmd_resp_wake (bus); +vfree (buf); }/* Pad read to blocksize for efficiency */
Greg Kroah-Hartman
maintainerPATCH 181/798 wifi: mwifiex: Detach sync cmd buffer on interrupted wait
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Fabio Estevam <[email protected]>
commit ef06882c7d8a7400b67d0d003b1008093dd589ed upstream.
mwifiex synchronous commands keep the caller-provided data buffer in cmd_node->data_buf. Several callers pass stack-allocated objects there.
If wait_event_interruptible_timeout() is interrupted, the caller can return and release that stack object while the firmware command is still the current command. A late firmware response then reaches the normal response handler, which can copy data through cmd_node->data_buf into the stale stack address.
This fixes a stack corruption observed during repeated association and disassociation cycles. The panic trace showed the command wait being interrupted immediately before a bad pointer dereference:
cmd_wait_q terminated: -512
Unable to handle kernel paging request at virtual address 002c583837384662 Kernel panic - not syncing: stack-protector: Kernel stack is corrupted ... Tainted: [M]=MACHINE_CHECK
The fault address decodes as little-endian ASCII:
0x002c583837384662 -> "bF878X,\0"
which is a fragment of the VERSION_EXT firmware string exposed as debugfs "verext":
w8997o-V4, RF878X, FP92, 16.92.21.p153.7
The same runs also showed corrupted control data containing:
0x2400372e333531 -> "153.7\0$"
which is the tail of the same VERSION_EXT string. This points at a late VERSION_EXT response writing through a stale stack-backed data_buf after the interrupted wait returned.
After cancelling pending commands on an interrupted or timed-out wait, detach the caller-owned data buffer from the still-current command. This preserves the existing command cancellation behaviour while preventing a late response from writing through a pointer whose lifetime ended with the waiting caller.
Tested on an i.MX8MP board using an 88W8997.
--- drivers/net/wireless/marvell/mwifiex/sta_ioctl.c | 12 ++++++++++++ 1 file changed, 12 insertions(+)
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c +12 -0
@@ -69,6 +69,18 @@ int mwifiex_wait_queue_complete(struct mmwifiex_dbg (adapter,ERROR ,"cmd_wait_q terminated: %d\n" , status);mwifiex_cancel_all_pending_cmd (adapter); + +/* The command response path writes through cmd_node->data_buf. +* On an interrupted wait, the caller can return and release a +* stack-allocated data_buf before a late firmware response is +* processed. Detach the caller-owned buffer from the current +* command so a late response cannot corrupt freed stack memory. +*/ +spin_lock_bh (&adapter->mwifiex_cmd_lock); +if (adapter->curr_cmd == cmd_queued) + adapter->curr_cmd->data_buf =NULL ; +spin_unlock_bh (&adapter->mwifiex_cmd_lock); +return status; }
Greg Kroah-Hartman
maintainerPATCH 182/798 wifi: rtl818x: initialize eeprom_93cx6 struct to zero
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stanislaw Gruszka <[email protected]>
commit 799b5f45cb8194ebd06c9c89e0afdad5bedd2cc5 upstream.
Commit 7738a7ab9d12 ("misc: eeprom: eeprom_93cx6: Add quirk for extra read clock cycle") added extra 'quirk' field to struct eeprom_93cx6.
Many existing users of eeprom_93cx6, including rtl818x drivers, allocate the structure on the stack without initializing all fields. As a result, the added quirk field has an undefined value and can randomly cause reading wrong data from the EEPROM.
Fix by initializing the structures with {}.
--- drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c | 2 +- drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-)
drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c +1 -1
@@ -1646,7 +1646,7 @@ static void rtl8180_eeprom_register_writstatic void rtl8180_eeprom_read (struct rtl8180_priv *priv) { -struct eeprom_93cx6 eeprom; +struct eeprom_93cx6 eeprom = {};int eeprom_cck_table_adr;u16 eeprom_val;int i;
drivers/net/wireless/realtek/rtl818x/rtl8187/dev.c +1 -1
@@ -1439,7 +1439,7 @@ static int rtl8187_probe(struct usb_intestruct usb_device *udev =interface_to_usbdev (intf);struct ieee80211_hw *dev;struct rtl8187_priv *priv; -struct eeprom_93cx6 eeprom; +struct eeprom_93cx6 eeprom = {};struct ieee80211_channel *channel;const char *chip_name;u16 txpwr, reg;
Greg Kroah-Hartman
maintainerPATCH 183/798 wifi: rtw88: Fix potential memory leak in rtw_txq_push_skb()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Abdun Nihaal <[email protected]>
commit 9f2948010764d708bda27369d09ce6f194abe8e3 upstream.
The skb passed to the rtw_hci_tx_write() is expected to be freed when the function fails, but the error path in rtw_txq_push_skb() does not free the skb before returning. This can lead to a memory leak in rtw_txq_push() where a dequeued skb is passed to rtw_txq_push_skb().
--- drivers/net/wireless/realtek/rtw88/tx.c | 1 + 1 file changed, 1 insertion(+)
drivers/net/wireless/realtek/rtw88/tx.c +1 -0
@@ -542,6 +542,7 @@ static int rtw_txq_push_skb(struct rtw_d ret =rtw_hci_tx_write (rtwdev, &pkt_info, skb);if (ret) {rtw_err (rtwdev,"failed to write TX skb to HCI\n" ); +ieee80211_free_txskb (rtwdev->hw, skb);return ret; } rtwtxq->last_push = jiffies;
Greg Kroah-Hartman
maintainerPATCH 184/798 vsock/virtio: flush works in dependency order
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chengfeng Ye <[email protected]>
commit 728836ebca239810f164262b10211ef59182f811 upstream.
virtio_vsock_remove() stops the virtqueues and then flushes each work item before freeing the enclosing virtio_vsock. The current order does not account for dependencies between those items: tx_work may queue send_pkt_work, and send_pkt_work may queue rx_work.
In particular, send_pkt_work can set restart_rx and release tx_lock. The remove path can then stop the queues and flush rx_work before send_pkt_work queues it. Although the later send_pkt_work flush waits for that producer to finish, nothing waits for the newly queued rx_work, so kfree(vsock) can race with it.
KASAN reported:
BUG: KASAN: slab-use-after-free in virtio_transport_rx_work+0x487/0x4b0 Read of size 8 at addr ffff888114c2b008 by task kworker/1:1/47 Workqueue: virtio_vsock virtio_transport_rx_work Call Trace: virtio_transport_rx_work+0x487/0x4b0 process_one_work+0x688/0x1120 worker_thread+0x45b/0xd10 Allocated by task 1: virtio_vsock_probe+0xef/0x6b0 Freed by task 84: kfree+0x131/0x3c0 virtio_vsock_remove+0xd1/0x100
Flush the works in producer-to-consumer order. virtio_vsock_vqs_del() has already disabled the queue callbacks and cleared the run flags, so after tx_work and send_pkt_work are drained, no source remains that can queue rx_work after its flush.
--- net/vmw_vsock/virtio_transport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
net/vmw_vsock/virtio_transport.c +1 -1
@@ -686,10 +686,10 @@ static void virtio_vsock_remove(struct v/* Other works can be queued before 'config->del_vqs()', so we flush * all works before to free the vsock object to avoid use after free. */ -flush_work (&vsock->rx_work);flush_work (&vsock->tx_work);flush_work (&vsock->event_work);flush_work (&vsock->send_pkt_work); +flush_work (&vsock->rx_work);mutex_unlock (&the_virtio_vsock_mutex);
Greg Kroah-Hartman
maintainerPATCH 185/798 w1: ds28e17: reject an oversize length on an I2C block read
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maoyi Xie <[email protected]>
commit 169ae5e65e5aaf213b6a578f6478a9fd2e523606 upstream.
w1_f19_i2c_master_transfer() is the master_xfer for the DS28E17 1-Wire to I2C bridge. On an I2C_M_RECV_LEN read, it takes the length from the device. The downstream slave puts a length byte in buf[0]. The driver then reads that many bytes into buf[1] with w1_f19_i2c_read().
buf[0] is controlled by the device and can be 0 to 255. w1_f19_i2c_read() only rejects a zero count. The caller buffer is I2C_SMBUS_BLOCK_MAX + 2, so 34 bytes. A length above 32 makes the read run past it, up to about 222 bytes out of bounds.
The SMBus core does check buf[0] against I2C_SMBUS_BLOCK_MAX. That check runs after master_xfer returns. By then the write is already done. i2c-algo-bit rejects an oversize length before it copies, and returns -EPROTO.
Reject a length above I2C_SMBUS_BLOCK_MAX at both RECV_LEN sites, the same way i2c-algo-bit does.
--- drivers/w1/slaves/w1_ds28e17.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/w1/slaves/w1_ds28e17.c +8 -0
@@ -389,6 +389,10 @@ static int w1_f19_i2c_master_transfer(st* another simple read in that case. */ if (msgs[i+1 ].flags &I2C_M_RECV_LEN ) { +if (msgs[i+1 ].buf[0 ] >I2C_SMBUS_BLOCK_MAX ) { + i = -EPROTO ; + goto error; + } result =w1_f19_i2c_read (sl, msgs[i+1 ].addr, &(msgs[i+1 ].buf[1 ]), msgs[i+1 ].buf[0 ]);if (result <0 ) {
@@ -415,6 +419,10 @@ static int w1_f19_i2c_master_transfer(st* another simple read in that case. */ if (msgs[i].flags &I2C_M_RECV_LEN ) { +if (msgs[i].buf[0 ] >I2C_SMBUS_BLOCK_MAX ) { + i = -EPROTO ; + goto error; + } result = w1_f19_i2c_read(sl, msgs[i].addr, &(msgs[i].buf[1]),
Greg Kroah-Hartman
maintainerPATCH 186/798 tpm: tpm_i2c_nuvoton: disable IRQ on wait timeout
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Myeonghun Pak <[email protected]>
commit 705c4ed0643366963547b2616d53165f2519c81f upstream.
i2c_nuvoton_wait_for_stat() enables the IRQ before waiting for the interrupt handler to report a status change. If the wait times out, or is interrupted before the handler runs, the function returns without balancing the enable_irq() call.
Disable the IRQ before leaving the failed wait path. Also preserve an interrupted wait's original error code instead of converting it to -ETIMEDOUT inside the helper.
--- drivers/char/tpm/tpm_i2c_nuvoton.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/char/tpm/tpm_i2c_nuvoton.c +4 -2
@@ -181,8 +181,10 @@ static int i2c_nuvoton_wait_for_stat(str timeout);if (rc >0 )return 0 ; -/* At this point we know that the SINT pin is asserted, so we -* do not need to do i2c_nuvoton_check_status */ + +disable_irq (priv->irq); +if (rc <0 ) +return rc; }else {unsigned long ten_msec, stop;bool status_valid;
Greg Kroah-Hartman
maintainerPATCH 187/798 signal: avoid shared siginfo namespace rewrites
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bradley Morgan <[email protected]>
commit d19cdc167e696714509e87d3f7ae765b6e164589 upstream.
send_signal_locked() rewrites sender ids for the target namespace. Group sends reuse the same siginfo, so one recipient can affect the next.
Copy the siginfo before changing it.
--- kernel/signal.c | 4 ++++ 1 file changed, 4 insertions(+)
kernel/signal.c +4 -0
@@ -1209,6 +1209,7 @@ static inline bool has_si_pid_and_uid(ststatic int send_signal (int sig,struct kernel_siginfo *info,struct task_struct *t,enum pid_type type) { +struct kernel_siginfo rewritten;/* Should SIGKILL or SIGSTOP be received by a pid namespace init? */ bool force = false;
@@ -1222,6 +1223,9 @@ static int send_signal(int sig, struct k/* SIGKILL and SIGSTOP is special or has ids */ struct user_namespace *t_user_ns; + rewritten = *info; + info = &rewritten; +rcu_read_lock (); t_user_ns =task_cred_xxx (t, user_ns);if (current_user_ns () != t_user_ns) {
Greg Kroah-Hartman
maintainerPATCH 188/798 timer: Keep debugobjects state consistent in migrate_timer_list()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Thomas Gleixner <[email protected]>
commit c793bbfc4a0a9f5a66978fc91559e9681748dbeb upstream.
When timers are migrated away from an offline CPU the debugobjects state gets corrupted. The timer is accounted as inactive on deletion, but the enqueue on the alive CPU lacks the activation call.
That used to work, but got broken when the trace point and the debug objects call got separated. That change missed to fixup migrate_timer_list().
Add the missing debug_timer_activate() invocation to fix it.
--- kernel/time/timer.c | 1 + 1 file changed, 1 insertion(+)
kernel/time/timer.c +1 -0
@@ -1963,6 +1963,7 @@ static void migrate_timer_list(struct ti timer = hlist_entry(head->first, struct timer_list, entry);detach_timer (timer, false); timer->flags = (timer->flags & ~TIMER_BASEMASK ) | cpu; +debug_timer_activate (timer);internal_add_timer (new_base, timer); } }
Greg Kroah-Hartman
maintainerPATCH 189/798 udf: Fix i_lenExtents truncation on 32-bit kernels
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhan Xusheng <[email protected]>
commit a5a5ed23b1340ff0f32a14a7ca8585f7c4e9b2e2 upstream.
In udf_do_extend_file() the total extent length is rounded up to a block boundary with:
iinfo->i_lenExtents = (iinfo->i_lenExtents + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
i_lenExtents is a __u64, but sb->s_blocksize is unsigned long. On 32-bit kernels unsigned long is 32-bit, so ~(sb->s_blocksize - 1) is a 32-bit value (e.g. 0xfffff800 for a 2 KiB block) that is zero-extended in the AND, clearing the upper 32 bits of i_lenExtents. For UDF files whose total extent length exceeds 4 GiB this truncates i_lenExtents when the file is extended, corrupting the tracked extent length.
Cast the block size to 64-bit before forming the mask. 64-bit kernels are unaffected.
--- fs/udf/inode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/udf/inode.c +1 -1
@@ -510,7 +510,7 @@ static int udf_do_extend_file(struct ino sb->s_blocksize - 1) & ~(sb->s_blocksize - 1)); iinfo->i_lenExtents = (iinfo->i_lenExtents + sb->s_blocksize -1 ) & - ~(sb->s_blocksize -1 ); + ~((u64 )sb->s_blocksize -1 ); }/* Can we merge with the previous extent? */
Greg Kroah-Hartman
maintainerPATCH 190/798 platform/chrome: sensorhub: Fix dropped timestamp events and log spam
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tzung-Bi Shih <[email protected]>
commit 9a3f43b30373c61477d0d3ab52946c05f9492bf9 upstream.
Commit 833740a2333c ("platform/chrome: sensorhub: Bound the EC-reported sensor number") evaluated the sensor_num against the bounds limit even for timestamp events. A timestamp event typically has a sensor_num of 0xff [1], causing the driver to flag it as invalid and skip to the next event.
As a result, we'd see a flooding of "Invalid sensor number 255 from EC" warning logs and these timestamp events were being dropped.
Move the bounds-check into cros_ec_sensor_ring_process_event() and evaluate it only after standalone timestamp events have already been processed and returned early.
[1] https://crrev.com/219ca6ef82ba266da788b673ee4ad50bd3ea1285/common/motion_sense_fifo.c#427
--- drivers/platform/chrome/cros_ec_sensorhub_ring.c | 27 ++++++++++++----------- 1 file changed, 15 insertions(+), 12 deletions(-)
drivers/platform/chrome/cros_ec_sensorhub_ring.c +15 -12
@@ -436,6 +436,21 @@ cros_ec_sensor_ring_process_event(struct fifo_timestamp, *current_timestamp, now); + +/* +* A standalone timestamp event typically has a sensor_num of +* 0xff. Return early here to prevent it from hitting the +* bounds check below and spamming the logs. +*/ +return false; + } + +/* Skip event if sensor_num from EC is out of bounds. */ +if (in->sensor_num >= sensorhub->sensor_num) { +dev_warn_ratelimited (sensorhub->dev, +"Invalid sensor number %u from EC\n" , + in->sensor_num); +return false; }if (in->flags &MOTIONSENSE_SENSOR_FLAG_ODR ) {
@@ -463,10 +478,6 @@ cros_ec_sensor_ring_process_event(structreturn true; } -if (in->flags &MOTIONSENSE_SENSOR_FLAG_TIMESTAMP ) -/* If we just have a timestamp, skip this entry. */ -return false; -/* Regular sample */ out->sensor_id = in->sensor_num; trace_cros_ec_sensorhub_data(in->sensor_num,
@@ -851,14 +862,6 @@ static void cros_ec_sensorhub_ring_handlfor (in = sensorhub->resp->fifo_read.data, j =0 ; j < number_data; j++, in++) { -/* Skip event if sensor_num from EC is out of bounds. */ -if (in->sensor_num >= sensorhub->sensor_num) { -dev_warn_ratelimited (sensorhub->dev, -"Invalid sensor number %u from EC\n" , - in->sensor_num); -continue ; - } - if (cros_ec_sensor_ring_process_event( sensorhub, fifo_info, fifo_timestamp,
Greg Kroah-Hartman
maintainerPATCH 191/798 usb: gadget: u_audio: Fix use-after-free on sound card disconnect
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sonali Pradhan <[email protected]>
commit 858965947081d10d41d9a1010a540d3d5eea958b upstream.
g_audio_cleanup() invokes snd_card_free_when_closed() to initiate sound card teardown and immediately frees the underlying struct snd_uac_chip context. However, snd_card_free_when_closed() returns asynchronously while ALSA control elements (kctls) remain open in userspace.
When userspace control applications access or close these open file descriptors, kctl callbacks attempt to dereference kctl->private_data pointing to &uac->c_prm or &uac->p_prm within the freed uac structure, resulting in a use-after-free (UAF) memory corruption.
Fix this issue by deferring the destruction of struct snd_uac_chip until all references to the ALSA sound card are released. Register a custom card->private_free callback (u_audio_card_free) during g_audio_setup() that frees uac and its associated playback/capture request and ring buffers only when the sound card reference count drops to zero.
--- drivers/usb/gadget/function/u_audio.c | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-)
drivers/usb/gadget/function/u_audio.c +18 -6
@@ -486,6 +486,20 @@ void u_audio_stop_playback(struct g_audio *audio_dev) }EXPORT_SYMBOL_GPL (u_audio_stop_playback); +static void u_audio_card_free (struct snd_card *card) +{ +struct snd_uac_chip *uac = card->private_data; + +if (!uac) +return ; + +kfree (uac->p_prm.ureq); +kfree (uac->c_prm.ureq); +kfree (uac->p_prm.rbuf); +kfree (uac->c_prm.rbuf); +kfree (uac); +} +int g_audio_setup (struct g_audio *g_audio,const char *pcm_name,const char *card_name) {
@@ -560,6 +574,8 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, goto fail; uac->card = card; + card->private_data = uac; + card->private_free = u_audio_card_free;/* * Create first PCM device
@@ -591,6 +607,8 @@ int g_audio_setup(struct g_audio *g_audio, const char *pcm_name, snd_fail:snd_card_free (card); +return err; + fail:kfree (uac->p_prm.ureq);kfree (uac->c_prm.ureq);
@@ -616,12 +634,6 @@ void g_audio_cleanup(struct g_audio *g_audio) card = uac->card;if (card)snd_card_free_when_closed (card); - -kfree (uac->p_prm.ureq); -kfree (uac->c_prm.ureq); -kfree (uac->p_prm.rbuf); -kfree (uac->c_prm.rbuf); -kfree (uac); }EXPORT_SYMBOL_GPL (g_audio_cleanup);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 192/798 net: skbuff: dont touch shared zerocopy state in skb_tx_error()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
[ Upstream commit f66bdb1cc0fcd227a062378f8be0b5873aa5600a ]
skb_tx_error() completes the zerocopy uarg and clears SKBFL_ALL_ZEROCOPY, and skb_zcopy_downgrade_managed() clears SKBFL_MANAGED_FRAG_REFS. Both live in skb_shinfo(), which every clone shares, while the caller only owns the reference it is about to drop. Through a clone it tells the producer its pages are free and drops SKBFL_SHARED_FRAG for an skb that is still in flight.
Open vSwitch reaches this with a non-last OVS_ACTION_ATTR_RECIRC:clone_execute() sends a skb_clone() into ovs_dp_process_packet() while do_execute_actions() keeps forwarding the original, and skb_clone() does not privatise the frags here -- skb_orphan_frags() returns early on SKBFL_DONT_ORPHAN. A flow miss on the clone then strips the marker from the packet still being forwarded, and a later local ESP delivery decrypts in place over frags it does not own privately.
Skip it for a cloned skb. Nothing is lost: skb_release_data() clears the zerocopy state once the last reference to the shared data goes.
--- net/core/skbuff.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
net/core/skbuff.c +5 -1
@@ -825,10 +825,14 @@ EXPORT_SYMBOL(skb_dump);* * Report xmit error if a device callback is tracking this skb. * skb must be freed afterwards. +* +* Does nothing for a cloned skb: the zerocopy state lives in +* skb_shinfo(), which the clones share. */ void skb_tx_error (struct sk_buff *skb) { -skb_zcopy_clear (skb, true); +if (skb && !skb_cloned (skb)) +skb_zcopy_clear (skb, true); }EXPORT_SYMBOL (skb_tx_error);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 193/798 net: skbuff: dont skb_tx_error() the source skb in skb_zerocopy()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Norbert Szetei <[email protected]>
[ Upstream commit 8ece906150128d5ec2462aabcc978c568433eca4 ]
skb_zerocopy() copies frags from @from into @to. On an skb_orphan_frags() failure it calls skb_tx_error(@from), a destructive operation on the source skb the copy helper does not own. That completes @from's zerocopy uarg and clears SKBFL_ALL_ZEROCOPY, including the SKBFL_SHARED_FRAG page-ownership marker.
Both callers already report the failure on their own drop path. nfnetlink_queue does it at nla_put_failure, and Open vSwitch does it in the flow-miss drop arm of ovs_dp_process_packet(), so nothing is lost by dropping it here.
On Open vSwitch's OVS_ACTION_ATTR_USERSPACE path the skb is not freed on this error: do_execute_actions() ignores output_userspace()'s return value and, unless the upcall was the last action, keeps forwarding the same skb through the flow's remaining actions. The uarg is completed while that skb is still in flight, telling the producer its buffers are free, and SKBFL_SHARED_FRAG is cleared on an skb the rest of the stack still handles. That flag is what makes esp_input() call skb_cow_data() instead of decrypting in place, so a later local ESP delivery can decrypt over frags the skb does not own privately.
Leave error reporting to the callers.
--- net/core/skbuff.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
net/core/skbuff.c +2 -3
@@ -3084,10 +3084,9 @@ skb_zerocopy(struct sk_buff *to, struct sk_buff *from, int len, int hlen) to->len += len + plen; to->data_len += len + plen; -if (unlikely (skb_orphan_frags (from,GFP_ATOMIC ))) { -skb_tx_error (from); +if (unlikely (skb_orphan_frags (from,GFP_ATOMIC )))return -ENOMEM ; - } +skb_zerocopy_clone (to, from,GFP_ATOMIC );for (i =0 ; i <skb_shinfo (from)->nr_frags; i++) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 194/798 net: openvswitch: fix kernel-doc warnings in internal headers
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ilya Maximets <[email protected]>
[ Upstream commit 6bb0dcb3d321c14be7ca33b71a149034d6a2cde8 ]
Some field descriptions were missing, some were not very accurate. Not touching the uAPI header or .c files for now.
Formatting of those comments isn't great in general, but at least they are not missing anything now.
Before:
$ ./scripts/kernel-doc -none -Wall net/openvswitch/*.h 2>&1 | wc -l 16
After:
$ ./scripts/kernel-doc -none -Wall net/openvswitch/*.h 2>&1 | wc -l 0
[ struct vport_upcall_stats_percpu doesn't exist in 6.2 and earlier
struct datapath doesn't have @upcall_portids in 5.14 and earlier ]
--- net/openvswitch/datapath.h | 20 ++++++++++++++------ net/openvswitch/vport.h | 8 ++++++++ 2 files changed, 22 insertions(+), 6 deletions(-)
net/openvswitch/datapath.h +14 -6
@@ -29,8 +29,8 @@* datapath. * @n_hit: Number of received packets for which a matching flow was found in * the flow table. -* @n_miss: Number of received packets that had no matching flow in the flow -* table. The sum of @n_hit and @n_miss is the number of packets that have +* @n_missed: Number of received packets that had no matching flow in the flow +* table. The sum of @n_hit and @n_missed is the number of packets that have * been received by the datapath. * @n_lost: Number of received packets that had no matching flow in the flow * table that could not be sent to userspace (normally due to an overflow in
@@ -40,6 +40,7 @@* up per packet. * @n_cache_hit: The number of received packets that had their mask found using * the mask cache. +* @syncp: Synchronization point for 64bit counters. */ struct dp_stats_percpu {u64 n_hit;
@@ -59,8 +60,10 @@ struct dp_stats_percpu {* ovs_mutex and RCU. * @stats_percpu: Per-CPU datapath statistics. * @net: Reference to net namespace. -* @max_headroom: the maximum headroom of all vports in this datapath; it will +* @user_features: Bitmap of enabled %OVS_DP_F_* features. +* @max_headroom: The maximum headroom of all vports in this datapath; it will * be used by all the internal vports in this dp. +* @meter_tbl: Meter table. * * Context: See the comment on locking at the top of datapath.c for additional * locking information.
@@ -107,10 +110,13 @@ struct ovs_skb_cb {#define OVS_CB (skb) ((struct ovs_skb_cb *)(skb)->cb)/** -* struct dp_upcall - metadata to include with a packet to send to userspace +* struct dp_upcall_info - metadata to include with a packet sent to userspace * @cmd: One of %OVS_PACKET_CMD_*. * @userdata: If nonnull, its variable-length value is passed to userspace as * %OVS_PACKET_ATTR_USERDATA. +* @actions: If nonnull, its variable-length value is passed to userspace as +* %OVS_PACKET_ATTR_ACTIONS. +* @actions_len: The length of the @actions. * @portid: Netlink portid to which packet should be sent. If @portid is 0 * then no packet is sent and the packet is accounted in the datapath's @n_lost * counter.
@@ -131,6 +137,10 @@ struct dp_upcall_info {* struct ovs_net - Per net-namespace data for ovs. * @dps: List of datapaths to enable dumping them all out. * Protected by genl_mutex. +* @dp_notify_work: A work notifier to handle port unregistering. +* @masks_rebalance: A work to periodically optimize flow table caches. +* @ct_limit_info: A hash table of conntrack zone connection limits. +* @xt_label: Whether connlables are configured for the network or not. */ struct ovs_net {struct list_head dps;
@@ -139,8 +149,6 @@ struct ovs_net {#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT )struct ovs_ct_limit_info *ct_limit_info;#endif - -/* Module reference for configuring conntrack. */ bool xt_label; };
net/openvswitch/vport.h +8 -0
@@ -90,6 +90,8 @@ struct vport {* none was supplied. * @dp: New vport's datapath. * @port_no: New vport's port number. +* @upcall_portids: %OVS_VPORT_ATTR_UPCALL_PID attribute from Netlink message, +* %NULL if none was supplied. */ struct vport_parms {const char *name;
@@ -117,6 +119,8 @@ struct vport_parms {* have any configuration. * @send: Send a packet on the device. * zero for dropped packets or negative for error. +* @owner: Module that implements this vport type. +* @list: List entry in the global list of vport types. */ struct vport_ops {enum ovs_vport_type type;
@@ -144,6 +148,8 @@ void ovs_vport_free(struct vport *);* * @vport: vport to access * +* Returns: A void pointer to a private data allocated in the @vport. +* * If a nonzero size was passed in priv_size of vport_alloc() a private data * area was allocated on creation. This allows that area to be accessed and * used for any purpose needed by the vport implementer.
@@ -158,6 +164,8 @@ static inline void *vport_priv(const struct vport *vport)* * @priv: Start of private data area. * +* Returns: A reference to a vport structure that contains @priv. +* * It is sometimes useful to translate from a pointer to the private data * area to the vport, such as in the case where the private data pointer is * the result of a hash table lookup. @priv must point to the start of the
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 195/798 openvswitch: Fix CT limit teardown use-after-free
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yuqi Xu <[email protected]>
[ Upstream commit 403f96c32c9e24600093d7d0c61c17daeedca957 ]
Packet processing uses CT limit state under RCU, while netns teardown frees that state under ovs_mutex. The CT limit pointer was neither removed from readers nor protected by a grace period, allowing packet processing to dereference the freed state.
An unprivileged user can trigger this bug from a user and network namespace, causing a slab-use-after-free in ovs_ct_execute() when the netns is torn down.
Publish the CT limit pointer through RCU, remove it before teardown, and wait for readers before freeing its contents. Keep ovs_mutex around individual CT limit updates, and use the RCU read-side lock while GET traverses the RCU-protected limit lists.
Netns teardown detaches the RCU-protected CT limit state in the pernet .pre_exit callback while holding ovs_mutex. The pernet core guarantees an RCU grace period between the .pre_exit and .exit callbacks, so the .exit callback completes the teardown without adding any extra synchronization.
The netlink command handlers do not need NULL checks because the userspace netlink socket holds an active reference to its network namespace while a request is processed. The per-netns exit path therefore cannot run concurrently with SET, DEL, or GET for that socket's namespace.
6.12+ doesn't have a 'family' argument in nf_conncount_init/destroy ]
--- net/openvswitch/conntrack.c | 122 +++++++++++++++++++++++------------- net/openvswitch/conntrack.h | 6 +- net/openvswitch/datapath.c | 10 ++- net/openvswitch/datapath.h | 8 ++- 4 files changed, 98 insertions(+), 48 deletions(-)
net/openvswitch/conntrack.c +79 -43
@@ -1156,10 +1156,14 @@ static int ovs_ct_check_limit(struct net *net, const struct ovs_conntrack_info *info) {struct ovs_net *ovs_net =net_generic (net, ovs_net_id); -const struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; +const struct ovs_ct_limit_info *ct_limit_info;u32 per_zone_limit, connections;u32 conncount_key; + ct_limit_info =rcu_dereference (ovs_net->ct_limit_info); +if (!ct_limit_info) +return 0 ; + conncount_key = info->zone.id; per_zone_limit =ct_limit_get (ct_limit_info, info->zone.id);
@@ -1860,43 +1864,56 @@ static void __ovs_ct_free_action(struct ovs_conntrack_info *ct_info)#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT )static int ovs_ct_limit_init (struct net *net,struct ovs_net *ovs_net) { +struct ovs_ct_limit_info *info;int i, err; - ovs_net->ct_limit_info =kmalloc (sizeof (*ovs_net->ct_limit_info), -GFP_KERNEL ); -if (!ovs_net->ct_limit_info) + info =kmalloc (sizeof (*info),GFP_KERNEL ); +if (!info)return -ENOMEM ; - ovs_net->ct_limit_info->default_limit =OVS_CT_LIMIT_DEFAULT ; - ovs_net->ct_limit_info->limits = + info->default_limit =OVS_CT_LIMIT_DEFAULT ; + info->limits =kmalloc_array (CT_LIMIT_HASH_BUCKETS ,sizeof (struct hlist_head ),GFP_KERNEL ); -if (!ovs_net->ct_limit_info->limits) { -kfree (ovs_net->ct_limit_info); +if (!info->limits) { +kfree (info);return -ENOMEM ; }for (i =0 ; i <CT_LIMIT_HASH_BUCKETS ; i++) -INIT_HLIST_HEAD (&ovs_net->ct_limit_info->limits[i]); +INIT_HLIST_HEAD (&info->limits[i]); - ovs_net->ct_limit_info->data = -nf_conncount_init (net,NFPROTO_INET ,sizeof (u32)); + info->data =nf_conncount_init (net,NFPROTO_INET ,sizeof (u32)); -if (IS_ERR (ovs_net->ct_limit_info->data)) { - err =PTR_ERR (ovs_net->ct_limit_info->data); -kfree (ovs_net->ct_limit_info->limits); -kfree (ovs_net->ct_limit_info); +if (IS_ERR (info->data)) { + err =PTR_ERR (info->data); +kfree (info->limits); +kfree (info);pr_err ("openvswitch: failed to init nf_conncount %d\n" , err);return err; } +rcu_assign_pointer (ovs_net->ct_limit_info, info);return 0 ; } -static void ovs_ct_limit_exit (struct net *net,struct ovs_net *ovs_net) +static void *ovs_ct_limit_exit_start (struct ovs_net *ovs_net) +{ +return rcu_replace_pointer (ovs_net->ct_limit_info,NULL , +lockdep_ovsl_is_held ()); +} + +/* The CT limit state must be detached by ovs_ct_limit_exit_start() and an +* RCU grace period must elapse before this function runs. The pernet core +* guarantees the grace period between the .pre_exit and .exit callbacks. +*/ +static void ovs_ct_limit_exit_finish (struct net *net,void *data) { -const struct ovs_ct_limit_info *info = ovs_net->ct_limit_info; +const struct ovs_ct_limit_info *info = data;int i; +if (!info) +return ; +nf_conncount_destroy (net,NFPROTO_INET , info->data);for (i =0 ; i <CT_LIMIT_HASH_BUCKETS ; ++i) {struct hlist_head *head = &info->limits[i];
@@ -1904,7 +1921,7 @@ static void ovs_ct_limit_exit(struct net *net, struct ovs_net *ovs_net)struct hlist_node *next;hlist_for_each_entry_safe (ct_limit, next, head, hlist_node) -kfree_rcu (ct_limit, rcu); +kfree (ct_limit); }kfree (info->limits);kfree (info);
@@ -1943,12 +1960,13 @@ static bool check_zone_id(int zone_id, u16 *pzone)return false; } -static int ovs_ct_limit_set_zone_limit (struct nlattr *nla_zone_limit, -struct ovs_ct_limit_info *info) +static int ovs_ct_limit_set_zone_limit (struct ovs_net *ovs_net, +struct nlattr *nla_zone_limit) {struct ovs_zone_limit *zone_limit; -int rem; +struct ovs_ct_limit_info *info;u16 zone; +int rem; rem =NLA_ALIGN (nla_len (nla_zone_limit)); zone_limit = (struct ovs_zone_limit *)nla_data (nla_zone_limit);
@@ -1957,6 +1975,7 @@ static int ovs_ct_limit_set_zone_limit(struct nlattr *nla_zone_limit,if (unlikely (zone_limit->zone_id ==OVS_ZONE_LIMIT_DEFAULT_ZONE )) {ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info); info->default_limit = zone_limit->limit;ovs_unlock (); } else if (unlikely(!check_zone_id(
@@ -1973,6 +1992,7 @@ static int ovs_ct_limit_set_zone_limit(struct nlattr *nla_zone_limit, ct_limit->limit = zone_limit->limit;ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info);ct_limit_set (info, ct_limit);ovs_unlock (); }
@@ -1987,12 +2007,13 @@ static int ovs_ct_limit_set_zone_limit(struct nlattr *nla_zone_limit,return 0 ; } -static int ovs_ct_limit_del_zone_limit (struct nlattr *nla_zone_limit, -struct ovs_ct_limit_info *info) +static int ovs_ct_limit_del_zone_limit (struct ovs_net *ovs_net, +struct nlattr *nla_zone_limit) {struct ovs_zone_limit *zone_limit; -int rem; +struct ovs_ct_limit_info *info;u16 zone; +int rem; rem =NLA_ALIGN (nla_len (nla_zone_limit)); zone_limit = (struct ovs_zone_limit *)nla_data (nla_zone_limit);
@@ -2001,6 +2022,7 @@ static int ovs_ct_limit_del_zone_limit(struct nlattr *nla_zone_limit,if (unlikely (zone_limit->zone_id ==OVS_ZONE_LIMIT_DEFAULT_ZONE )) {ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info); info->default_limit =OVS_CT_LIMIT_DEFAULT ;ovs_unlock (); } else if (unlikely(!check_zone_id(
@@ -2008,6 +2030,7 @@ static int ovs_ct_limit_del_zone_limit(struct nlattr *nla_zone_limit,OVS_NLERR (true,"zone id is out of range" ); }else {ovs_lock (); + info =ovsl_dereference (ovs_net->ct_limit_info);ct_limit_del (info, zone);ovs_unlock (); }
@@ -2051,6 +2074,7 @@ static int __ovs_ct_limit_get_zone_limit(struct net *net,return nla_put_nohdr (reply,sizeof (zone_limit), &zone_limit); } +/* Called with RCU read lock held. */ static int ovs_ct_limit_get_zone_limit(struct net *net, struct nlattr *nla_zone_limit, struct ovs_ct_limit_info *info,
@@ -2074,12 +2098,10 @@ static int ovs_ct_limit_get_zone_limit(struct net *net, &zone))) { OVS_NLERR(true, "zone id is out of range"); } else { -rcu_read_lock (); limit =ct_limit_get (info, zone); err =__ovs_ct_limit_get_zone_limit ( net, info->data, zone, limit, reply); -rcu_read_unlock ();if (err)return err; }
@@ -2094,6 +2116,7 @@ static int ovs_ct_limit_get_zone_limit(struct net *net,return 0 ; } +/* Called with RCU read lock held. */ static int ovs_ct_limit_get_all_zone_limit (struct net *net,struct ovs_ct_limit_info *info,struct sk_buff *reply)
@@ -2106,19 +2129,16 @@ static int ovs_ct_limit_get_all_zone_limit(struct net *net,if (err)return err; -rcu_read_lock ();for (i =0 ; i <CT_LIMIT_HASH_BUCKETS ; ++i) { head = &info->limits[i];hlist_for_each_entry_rcu (ct_limit, head, hlist_node) { err =__ovs_ct_limit_get_zone_limit (net, info->data, ct_limit->zone, ct_limit->limit, reply);if (err) - goto exit_err; +return err; } } -exit_err: -rcu_read_unlock ();return err; }
@@ -2128,7 +2148,6 @@ static int ovs_ct_limit_cmd_set(struct sk_buff *skb, struct genl_info *info)struct sk_buff *reply;struct ovs_header *ovs_reply_header;struct ovs_net *ovs_net =net_generic (sock_net (skb->sk), ovs_net_id); -struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info;int err; reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_SET,
@@ -2141,8 +2160,8 @@ static int ovs_ct_limit_cmd_set(struct sk_buff *skb, struct genl_info *info) goto exit_err; } - err =ovs_ct_limit_set_zone_limit (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ], - ct_limit_info); + err =ovs_ct_limit_set_zone_limit (ovs_net, + a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ]);if (err) goto exit_err;
@@ -2162,7 +2181,6 @@ static int ovs_ct_limit_cmd_del(struct sk_buff *skb, struct genl_info *info)struct sk_buff *reply;struct ovs_header *ovs_reply_header;struct ovs_net *ovs_net =net_generic (sock_net (skb->sk), ovs_net_id); -struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info;int err; reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_DEL,
@@ -2175,8 +2193,8 @@ static int ovs_ct_limit_cmd_del(struct sk_buff *skb, struct genl_info *info) goto exit_err; } - err =ovs_ct_limit_del_zone_limit (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ], - ct_limit_info); + err =ovs_ct_limit_del_zone_limit (ovs_net, + a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ]);if (err) goto exit_err;
@@ -2196,7 +2214,7 @@ static int ovs_ct_limit_cmd_get(struct sk_buff *skb, struct genl_info *info)struct ovs_header *ovs_reply_header;struct net *net =sock_net (skb->sk);struct ovs_net *ovs_net =net_generic (net, ovs_net_id); -struct ovs_ct_limit_info *ct_limit_info = ovs_net->ct_limit_info; +struct ovs_ct_limit_info *ct_limit_info;int err; reply = ovs_ct_limit_cmd_reply_start(info, OVS_CT_LIMIT_CMD_GET,
@@ -2210,18 +2228,19 @@ static int ovs_ct_limit_cmd_get(struct sk_buff *skb, struct genl_info *info) goto exit_err; } +rcu_read_lock (); + ct_limit_info =rcu_dereference (ovs_net->ct_limit_info);if (a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ]) { err =ovs_ct_limit_get_zone_limit ( net, a[OVS_CT_LIMIT_ATTR_ZONE_LIMIT ], ct_limit_info, reply); -if (err) - goto exit_err; }else { err =ovs_ct_limit_get_all_zone_limit (net, ct_limit_info, reply); -if (err) - goto exit_err; } +rcu_read_unlock (); +if (err) + goto exit_err;nla_nest_end (reply, nla_reply);genlmsg_end (reply, ovs_reply_header);
@@ -2293,12 +2312,29 @@ int ovs_ct_init(struct net *net)return err; } -void ovs_ct_exit (struct net *net) +/* Must be called with ovs_mutex held. Detaches the RCU-protected +* ct_limit_info and stores it in ovs_net->ct_limit_exit_data for +* ovs_ct_exit_finish() to complete the teardown after an RCU grace period. +*/ +void ovs_ct_exit_start (struct net *net__maybe_unused ) +{ +#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) +struct ovs_net *ovs_net =net_generic (net, ovs_net_id); + + ovs_net->ct_limit_exit_data =ovs_ct_limit_exit_start (ovs_net); +#endif +} + +/* Completes the CT limit teardown. The pernet core guarantees an RCU +* grace period between detaching the state in ovs_ct_exit_start() and +* this call, so no RCU readers remain. +*/ +void ovs_ct_exit_finish (struct net *net) {struct ovs_net *ovs_net =net_generic (net, ovs_net_id);#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) -ovs_ct_limit_exit (net, ovs_net); +ovs_ct_limit_exit_finish (net, ovs_net->ct_limit_exit_data);#endif if (ovs_net->xt_label)
net/openvswitch/conntrack.h +4 -2
@@ -14,7 +14,8 @@ enum ovs_key_attr;#if IS_ENABLED (CONFIG_NF_CONNTRACK )int ovs_ct_init (struct net *); -void ovs_ct_exit (struct net *); +void ovs_ct_exit_start (struct net *net); +void ovs_ct_exit_finish (struct net *net);bool ovs_ct_verify (struct net *,enum ovs_key_attr attr); int ovs_ct_copy_action(struct net *, const struct nlattr *, const struct sw_flow_key *, struct sw_flow_actions **,
@@ -39,7 +40,8 @@ void ovs_ct_free_action(const struct nlattr *a);static inline int ovs_ct_init (struct net *net) {return 0 ; } -static inline void ovs_ct_exit (struct net *net) { } +static inline void ovs_ct_exit_start (struct net *net) { } +static inline void ovs_ct_exit_finish (struct net *net) { }static inline bool ovs_ct_verify (struct net *net,int attr) {
net/openvswitch/datapath.c +9 -1
@@ -2599,6 +2599,13 @@ static void __net_exit list_vports_from_net(struct net *net, struct net *dnet, } } +static void __net_exit ovs_pre_exit_net(struct net *dnet) +{ +ovs_lock (); +ovs_ct_exit_start (dnet); +ovs_unlock (); +} + static void __net_exit ovs_exit_net(struct net *dnet) {struct datapath *dp, *dp_next;
@@ -2609,7 +2616,7 @@ static void __net_exit ovs_exit_net(struct net *dnet)ovs_lock (); -ovs_ct_exit (dnet); +ovs_ct_exit_finish (dnet);list_for_each_entry_safe (dp, dp_next, &ovs_net->dps, list_node)__dp_destroy (dp);
@@ -2633,6 +2640,7 @@ static void __net_exit ovs_exit_net(struct net *dnet)static struct pernet_operations ovs_net_ops = { .init = ovs_init_net, + .pre_exit = ovs_pre_exit_net, .exit = ovs_exit_net, .id = &ovs_net_id, .size =sizeof (struct ovs_net ),
net/openvswitch/datapath.h +6 -2
@@ -139,7 +139,10 @@ struct dp_upcall_info {* Protected by genl_mutex. * @dp_notify_work: A work notifier to handle port unregistering. * @masks_rebalance: A work to periodically optimize flow table caches. -* @ct_limit_info: A hash table of conntrack zone connection limits. +* @ct_limit_info: Hash table of conntrack zone connection limits. Protected +* by RCU; updates and teardown are serialized by ovs_mutex. May be NULL during +* netns teardown. +* @ct_limit_exit_data: CT limit state detached at .pre_exit, freed at .exit. * @xt_label: Whether connlables are configured for the network or not. */ struct ovs_net {
@@ -147,7 +150,8 @@ struct ovs_net {struct work_struct dp_notify_work;struct delayed_work masks_rebalance;#if IS_ENABLED (CONFIG_NETFILTER_CONNCOUNT ) -struct ovs_ct_limit_info *ct_limit_info; +struct ovs_ct_limit_info __rcu *ct_limit_info; +struct ovs_ct_limit_info *ct_limit_exit_data;#endif bool xt_label; };
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 196/798 netfilter: nf_tables: make nft_object rhltable per table
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pablo Neira Ayuso <[email protected]>
commit f4f699790590bd0896c48a71e9232a65198f92f0 upstream.
The nft_object rhltable is global, this allows for accessing objects that are being dismangled from lookup path by other existing netns. Given the nft_obj_destroy() releases the object inmediately, this might lead to use-after-free of these objects that are being released. Make the existing rhltable per table to address this issue to deal with with the nft_rcv_nl_event() path too.
Update nft_obj_lookup() to take the table as non-const, otherwise, compiler complains when passing the objname_ht to rhltable_lookup().
[ 5.10: More extensive conflicts than 6.1 in nf_tables_api.c because 5.10
lacks several mainline refactors: 0be908750162 ("netfilter: nf_tables:
pass nft_table to destroy function", v6.11), e169285f8c56 ("netfilter:
nf_tables: do not store nft_ctx in transaction objects", v6.11), f80a612dd77c ("netfilter: nf_tables: add support to destroy operation", v6.3), 797d49805ddc ("netfilter: nfnetlink: pass struct nfnl_info to rcu callbacks", v5.13) and 6001a930ce03 ("netfilter:
nftables: introduce table ownership", v5.12). Resolved by: destroying the per-table objname_ht via ctx->table in nf_tables_table_destroy(); dropping only the const on the local table in nf_tables_getobj() (which still uses the pre-nfnl_info API); passing the owning table trans->ctx.table to nft_obj_del() in the commit and abort paths (struct nft_trans still embeds an nft_ctx and 5.10 has no NFT_MSG_DESTROYOBJ case); and removing the global nft_objname_ht rhltable_init/destroy from module init, keeping 5.10's numeric error labels. The header and all other hunks applied cleanly. ]
--- include/net/netfilter/nf_tables.h | 4 +++- net/netfilter/nf_tables_api.c | 34 +++++++++++++++---------------- 2 files changed, 19 insertions(+), 19 deletions(-)
include/net/netfilter/nf_tables.h +3 -1
@@ -1100,6 +1100,7 @@ static inline void nft_use_inc_restore(u32 *use)* @sets: sets in the table * @objects: stateful objects in the table * @flowtables: flow tables in the table +* @objname_ht: hashtable for objects lookup by name * @hgenerator: handle generator state * @handle: table handle * @use: number of chain references to this table
@@ -1115,6 +1116,7 @@ struct nft_table {struct list_head sets;struct list_head objects;struct list_head flowtables; +struct rhltable objname_ht;u64 hgenerator;u64 handle;u32 use;
@@ -1187,7 +1189,7 @@ static inline void *nft_obj_data(const struct nft_object *obj)#define nft_expr_obj (expr) *((struct nft_object **)nft_expr_priv(expr))struct nft_object *nft_obj_lookup (const struct net *net, -const struct nft_table *table, +struct nft_table *table,const struct nlattr *nla,u32 objtype,u8 genmask);
net/netfilter/nf_tables_api.c +16 -18
@@ -44,8 +44,6 @@ enum { NFT_VALIDATE_DO, }; -static struct rhltable nft_objname_ht; -static u32 nft_chain_hash (const void *data,u32 len,u32 seed);static u32 nft_chain_hash_obj (const void *data,u32 len,u32 seed);static int nft_chain_hash_cmp (struct rhashtable_compare_arg *,const void *);
@@ -1295,6 +1293,10 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,if (err) goto err_chain_ht; + err =rhltable_init (&table->objname_ht, &nft_objname_ht_params); +if (err <0 ) + goto err_obj_ht; +INIT_LIST_HEAD (&table->chains);INIT_LIST_HEAD (&table->sets);INIT_LIST_HEAD (&table->objects);
@@ -1311,6 +1313,8 @@ static int nf_tables_newtable(struct net *net, struct sock *nlsk,list_add_tail_rcu (&table->list, &nft_net->tables);return 0 ; err_trans: +rhltable_destroy (&table->objname_ht); +err_obj_ht:rhltable_destroy (&table->chains_ht); err_chain_ht:kfree (table->udata);
@@ -1469,6 +1473,7 @@ static void nf_tables_table_destroy(struct nft_ctx *ctx)return ;rhltable_destroy (&ctx->table->chains_ht); +rhltable_destroy (&ctx->table->objname_ht);kfree (ctx->table->name);kfree (ctx->table->udata);kfree (ctx->table);
@@ -6160,7 +6165,7 @@ void nft_unregister_obj(struct nft_object_type *obj_type)EXPORT_SYMBOL_GPL (nft_unregister_obj);struct nft_object *nft_obj_lookup (const struct net *net, -const struct nft_table *table, +struct nft_table *table,const struct nlattr *nla,u32 objtype,u8 genmask) {
@@ -6176,7 +6181,7 @@ struct nft_object *nft_obj_lookup(const struct net *net, !lockdep_commit_lock_is_held(net));rcu_read_lock (); - list =rhltable_lookup (&nft_objname_ht, &k, nft_objname_ht_params); + list =rhltable_lookup (&table->objname_ht, &k, nft_objname_ht_params);if (!list) goto out;
@@ -6450,7 +6455,7 @@ static int nf_tables_newobj(struct net *net, struct sock *nlsk,if (err <0 ) goto err_trans; - err =rhltable_insert (&nft_objname_ht, &obj->rhlhead, + err =rhltable_insert (&table->objname_ht, &obj->rhlhead, nft_objname_ht_params);if (err <0 ) goto err_obj_ht;
@@ -6636,7 +6641,7 @@ static int nf_tables_getobj(struct net *net, struct sock *nlsk,const struct nfgenmsg *nfmsg =nlmsg_data (nlh);u8 genmask =nft_genmask_cur (net);int family = nfmsg->nfgen_family; -const struct nft_table *table; +struct nft_table *table;struct nft_object *obj;struct sk_buff *skb2;bool reset = false;
@@ -8192,9 +8197,9 @@ static void nf_tables_commit_chain(struct net *net, struct nft_chain *chain)nf_tables_commit_chain_free_rules_old (g0); } -static void nft_obj_del (struct nft_object *obj) +static void nft_obj_del (struct nft_table *table,struct nft_object *obj) { -rhltable_remove (&nft_objname_ht, &obj->rhlhead, nft_objname_ht_params); +rhltable_remove (&table->objname_ht, &obj->rhlhead, nft_objname_ht_params);list_del_rcu (&obj->list); }
@@ -8774,7 +8779,7 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb) }break ;case NFT_MSG_DELOBJ : -nft_obj_del (nft_trans_obj (trans)); +nft_obj_del (trans->ctx.table,nft_trans_obj (trans));nf_tables_obj_notify (&trans->ctx,nft_trans_obj (trans),NFT_MSG_DELOBJ );break ;
@@ -9022,7 +9027,7 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)nft_trans_destroy (trans); }else {nft_use_dec_restore (&trans->ctx.table->use); -nft_obj_del (nft_trans_obj (trans)); +nft_obj_del (trans->ctx.table,nft_trans_obj (trans)); }break ;case NFT_MSG_DELOBJ :
@@ -9679,7 +9684,7 @@ static void __nft_release_table(struct net *net, struct nft_table *table)nft_set_destroy (&ctx, set); }list_for_each_entry_safe (obj, ne, &table->objects, list) { -nft_obj_del (obj); +nft_obj_del (table, obj);nft_use_dec (&table->use);nft_obj_destroy (&ctx, obj); }
@@ -9786,10 +9791,6 @@ static int __init nf_tables_module_init(void)if (err <0 ) goto err3; - err =rhltable_init (&nft_objname_ht, &nft_objname_ht_params); -if (err <0 ) - goto err4; - err =nft_offload_init ();if (err <0 ) goto err5;
@@ -9805,8 +9806,6 @@ static int __init nf_tables_module_init(void) err6:nft_offload_exit (); err5: -rhltable_destroy (&nft_objname_ht); -err4:unregister_netdevice_notifier (&nf_tables_flowtable_notifier); err3:nf_tables_core_module_exit ();
@@ -9829,7 +9828,6 @@ static void __exit nf_tables_module_exit(void)cancel_work_sync (&trans_gc_work);cancel_work_sync (&trans_destroy_work);rcu_barrier (); -rhltable_destroy (&nft_objname_ht);nf_tables_core_module_exit (); }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 197/798 RDMA/rxe: Fix over copying in get_srq_wqe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bob Pearson <[email protected]>
[ Upstream commit ec0fa2445c18ec49a0b7ee0aaa82d1ec00968fc9 ]
Currently get_srq_wqe() in rxe_resp.c copies the maximum possible number of bytes from the wqe into the QPs copy of the SRQ wqe. This is usually extra work and risks reading past the end of the SRQ circular buffer if the SRQ is configured with less than the maximum possible number of SGEs.
Check the number of SGEs is not too large.
Compute the actual number of bytes in the WR and copy only those.
[doebel: context adjustment from upstream patch to 5.10. needed as a prerequisite
for "RDMA/rxe: Fix TOCTOU heap overflow in get_srq_wqe" ]
--- drivers/infiniband/sw/rxe/rxe_resp.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/infiniband/sw/rxe/rxe_resp.c +8 -2
@@ -292,6 +292,7 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)struct rxe_queue *q = srq->rq.queue;struct rxe_recv_wqe *wqe;struct ib_event ev; +size_t size;if (srq->error)return RESPST_ERR_RNR ;
@@ -304,8 +305,13 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)return RESPST_ERR_RNR ; } -/* note kernel and user space recv wqes have same size */ -memcpy (&qp->resp.srq_wqe, wqe,sizeof (qp->resp.srq_wqe)); +/* don't trust user space data */ +if (unlikely (wqe->dma.num_sge > srq->rq.max_sge)) { +pr_warn ("%s: invalid num_sge in SRQ entry\n" , __func__); +return RESPST_ERR_MALFORMED_WQE ; + } + size =sizeof (wqe) + wqe->dma.num_sge*sizeof (struct rxe_sge ); +memcpy (&qp->resp.srq_wqe, wqe, size); qp->resp.wqe = &qp->resp.srq_wqe.wqe;advance_consumer (q);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 198/798 RDMA/rxe: Missing unlock on error in get_srq_wqe()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dan Carpenter <[email protected]>
[ Upstream commit 36941dfe0e8c3e2da7851b9648fd74bd3a3e78ce ]
This error path needs to unlock before returning.
[doebel: Clean cherry-pick. Needed as a prerequisiste for
"RDMA/rxe: Fix TOCTOU heap overflow in get_srq_wqe" ]
--- drivers/infiniband/sw/rxe/rxe_resp.c | 1 + 1 file changed, 1 insertion(+)
drivers/infiniband/sw/rxe/rxe_resp.c +1 -0
@@ -307,6 +307,7 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)/* don't trust user space data */ if (unlikely (wqe->dma.num_sge > srq->rq.max_sge)) { +spin_unlock_bh (&srq->rq.consumer_lock);pr_warn ("%s: invalid num_sge in SRQ entry\n" , __func__);return RESPST_ERR_MALFORMED_WQE ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 199/798 RDMA/rxe: Use the correct size of wqe when processing SRQ
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bob Pearson <[email protected]>
[ Upstream commit e2a05339fa1188b6b37540f4611893ac4c534fa2 ]
The memcpy() that copies a WQE from a SRQ the QP uses an incorrect size. The size should have been the size of the rxe_send_wqe struct not the size of a pointer to it. The result is that IO operations using a SRQ on the responder side will fail.
[doebel: Clean cherry-pick. Needed as a prerequisite for
"RDMA/rxe: Fix TOCTOU heap overflow in get_srq_wqe" ]
--- drivers/infiniband/sw/rxe/rxe_resp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/sw/rxe/rxe_resp.c +1 -1
@@ -311,7 +311,7 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)pr_warn ("%s: invalid num_sge in SRQ entry\n" , __func__);return RESPST_ERR_MALFORMED_WQE ; } - size =sizeof (wqe) + wqe->dma.num_sge*sizeof (struct rxe_sge ); + size =sizeof (*wqe) + wqe->dma.num_sge*sizeof (struct rxe_sge );memcpy (&qp->resp.srq_wqe, wqe, size); qp->resp.wqe = &qp->resp.srq_wqe.wqe;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 200/798 RDMA/rxe: Fix TOCTOU heap overflow in get_srq_wqe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Tristan Madani <[email protected]>
[ Upstream commit 22b8fbded65b8c441b634a185f8da67657df6c50 ]
get_srq_wqe() reads wqe->dma.num_sge from the shared receive queue buffer, which is mapped into userspace. It validates num_sge against max_sge, but then re-reads the same field to calculate the memcpy size. A concurrent userspace thread can modify num_sge between validation and use, causing a heap buffer overflow when copying the WQE into qp->resp.srq_wqe.
Read num_sge into a local variable and use it for both the bounds check and the size calculation.
--- drivers/infiniband/sw/rxe/rxe_resp.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
drivers/infiniband/sw/rxe/rxe_resp.c +4 -2
@@ -292,6 +292,7 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp)struct rxe_queue *q = srq->rq.queue;struct rxe_recv_wqe *wqe;struct ib_event ev; +unsigned int num_sge;size_t size;if (srq->error)
@@ -306,12 +307,13 @@ static enum resp_states get_srq_wqe(struct rxe_qp *qp) }/* don't trust user space data */ -if (unlikely (wqe->dma.num_sge > srq->rq.max_sge)) { + num_sge = wqe->dma.num_sge; +if (unlikely (num_sge > srq->rq.max_sge)) {spin_unlock_bh (&srq->rq.consumer_lock);pr_warn ("%s: invalid num_sge in SRQ entry\n" , __func__);return RESPST_ERR_MALFORMED_WQE ; } - size =sizeof (*wqe) + wqe->dma.num_sge*sizeof (struct rxe_sge ); + size =sizeof (*wqe) + num_sge *sizeof (struct rxe_sge );memcpy (&qp->resp.srq_wqe, wqe, size); qp->resp.wqe = &qp->resp.srq_wqe.wqe;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 201/798 entry: Fix seccomp bypass after ptrace with TSYNC
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jinjie Ruan <[email protected]>
commit 4a3591287fb7f808e209b4974ed337f609a2006b upstream.
Sashiko review pointed out the following issue.
If a thread is stopped in syscall_trace_enter() for ptrace, another thread can install a seccomp filter with SECCOMP_FILTER_FLAG_TSYNC (e.g., via seccomp_attach_filter()). This will successfully set SYSCALL_WORK_SECCOMP on the stopped thread, but syscall_trace_enter() evaluates a cached 'work' variable sampled on entry. Consequently, the subsequent check for SYSCALL_WORK_SECCOMP misses the newly assigned flag, and the filter is silently bypassed.
This race condition could allow an unprivileged process to execute a prohibited system call (e.g., execve) that the newly installed filter was intended to block, especially since the tracer might have modified the system call number during the ptrace stop.
Fix this by re-reading the syscall_work flags after ptrace handling, so that any new SYSCALL_WORK_SECCOMP flag set by another thread via TSYNC during the ptrace stop is observed before the subsequent seccomp check.
--- kernel/entry/common.c | 3 +++ 1 file changed, 3 insertions(+)
kernel/entry/common.c +3 -0
@@ -51,6 +51,9 @@ static long syscall_trace_enter(struct pt_regs *regs, long syscall, ret =arch_syscall_enter_tracehook (regs);if (ret || (ti_work & _TIF_SYSCALL_EMU))return -1L ; + +/* ptrace might have changed work flags */ + ti_work =READ_ONCE (current_thread_info ()->flags); }/* Do seccomp after ptrace, to catch any tracer changes. */
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 202/798 fsnotify: Fix stale object mask after concurrent mark updates
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Youngjae Kwon <[email protected]>
[ Upstream commit e422777fdd4746de1109575c51e65038d4c5c1be ]
When a mark gets a new event bit, fanotify and inotify may avoid recalculating the object mask if the cached aggregate already contains that bit. This is racy with a recalculation triggered by a concurrent update to another mark on the same connector.
The concurrent scan can read the mark before the new bit is added, while the updater reads the old aggregate before that scan publishes its result. The updater then skips recalculation and the scan publishes a mask without the bit, leaving the object mask stale after both updates complete.
This can be reproduced with two fanotify groups watching the same inode:
one thread removes FAN_MODIFY from one existing mark while another thread adds FAN_MODIFY to the other mark. After both fanotify_mark() calls return, writes can fail to produce FAN_MODIFY for the group whose mark now contains the bit. This was reproduced on an unmodified v6.12.95 kernel. The equivalent inotify interleaving loses IN_MODIFY events.
For normal fanotify additions, recalculate whenever the raw mark mask changes. The normal mask is not cleared asynchronously, so an unchanged addition cannot introduce missing interest. Always recalculate ignore-mask updates because FS_MODIFY handling may clear the ignore mask without taking mark->lock, making snapshot comparisons unreliable.
Always recalculate after updating an existing inotify watch. Its replace path temporarily sets mark->mask to zero, so a concurrent scan can observe zero even when the old and final masks are equal. Assigning the replacement mask directly would avoid the transient zero, but existing-watch updates are infrequent, so unconditional recalculation is simpler.
[yjkwon0026: Resolve the inotify conflict by retaining the branch-native inode->i_fsnotify_marks argument to fsnotify_recalc_mask(). This tree lacks 35ceae44742e ("fsnotify: Avoid data race between fsnotify_recalc_mask() and fsnotify_object_watched()") and 4520b96b8136 ("fsnotify: inotify: pass mark connector to fsnotify_recalc_mask()"). The differing READ_ONCE() line and connector call are in the conditional deleted by this patch, so neither commit is a prerequisite for this fix.]
--- fs/notify/fanotify/fanotify_user.c | 12 +++++++----- fs/notify/inotify/inotify_user.c | 15 +-------------- 2 files changed, 8 insertions(+), 19 deletions(-)
fs/notify/fanotify/fanotify_user.c +7 -5
@@ -1114,16 +1114,18 @@ static bool fanotify_mark_update_flags(struct fsnotify_mark *fsn_mark,static bool fanotify_mark_add_to_mask (struct fsnotify_mark *fsn_mark,__u32 mask,unsigned int fan_flags) { +__u32 old_mask;bool recalc;spin_lock (&fsn_mark->lock); -if (!(fan_flags &FANOTIFY_MARK_IGNORE_BITS )) +if (!(fan_flags &FANOTIFY_MARK_IGNORE_BITS )) { + old_mask = fsn_mark->mask; fsn_mark->mask |= mask; -else + recalc = old_mask != fsn_mark->mask; + }else { fsn_mark->ignore_mask |= mask; - - recalc =fsnotify_calc_mask (fsn_mark) & - ~fsnotify_conn_mask (fsn_mark->connector); + recalc = true; + } recalc |=fanotify_mark_update_flags (fsn_mark, fan_flags);spin_unlock (&fsn_mark->lock);
fs/notify/inotify/inotify_user.c +1 -14
@@ -527,7 +527,6 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, {struct fsnotify_mark *fsn_mark;struct inotify_inode_mark *i_mark; -__u32 old_mask, new_mask;int replace = !(arg &IN_MASK_ADD );int create = (arg &IN_MASK_CREATE );int ret;
@@ -543,27 +542,15 @@ static int inotify_update_existing_watch(struct fsnotify_group *group, i_mark = container_of(fsn_mark, struct inotify_inode_mark, fsn_mark);spin_lock (&fsn_mark->lock); - old_mask = fsn_mark->mask;if (replace) { fsn_mark->mask =0 ; fsn_mark->flags &= ~INOTIFY_MARK_FLAGS ; } fsn_mark->mask |=inotify_arg_to_mask (inode, arg); fsn_mark->flags |=inotify_arg_to_flags (arg); - new_mask = fsn_mark->mask;spin_unlock (&fsn_mark->lock); -if (old_mask != new_mask) { -/* more bits in old than in new? */ -int dropped = (old_mask & ~new_mask); -/* more bits in this fsn_mark than the inode's mask? */ -int do_inode = (new_mask & ~inode->i_fsnotify_mask); - -/* update the inode with this new fsn_mark */ -if (dropped || do_inode) -fsnotify_recalc_mask (inode->i_fsnotify_marks); - - } +fsnotify_recalc_mask (inode->i_fsnotify_marks);/* return the wd */ ret = i_mark->wd;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 203/798 tcp: fix potential race in tcp_v6_syn_recv_sock()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Eric Dumazet <[email protected]>
[ Upstream commit 858d2a4f67ff69e645a43487ef7ea7f28f06deae ]
Code in tcp_v6_syn_recv_sock() after the call to tcp_v4_syn_recv_sock() is done too late.
After tcp_v4_syn_recv_sock(), the child socket is already visible from TCP ehash table and other cpus might use it.
Since newinet->pinet6 is still pointing to the listener ipv6_pinfo bad things can happen as syzbot found.
Move the problematic code in tcp_v6_mapped_child_init() and call this new helper from tcp_v4_syn_recv_sock() before the ehash insertion.
This allows the removal of one tcp_sync_mss(), since tcp_v4_syn_recv_sock() will call it with the correct context.
[florian:
- net/ipv6/tcp_ipv6.c:
- Set newnp->ipv6_fl_list = NULL instead of newinet->ipv6_fl_list = NULL, as ipv6_fl_list is in struct ipv6_pinfo.
- Guarded af_specific assignment with #ifdef CONFIG_TCP_MD5SIG instead of checking CONFIG_TCP_AO.
- Used if (tcp_inet6_sk(sk)->repflow) instead of inet6_test_bit(REPFLOW, sk).
- net/smc/af_smc.c:
- Dropped changes to net/smc/af_smc.c because SMC did not implement
`smc_tcp_syn_recv_sock()` in 5.10.y (added in 5.14 via commit e94a869818ab).
- net/dccp/:
- Updated syn_recv_sock implementations and call sites for DCCP, which was removed in upstream kernels prior to this commit.]
--- include/net/inet_connection_sock.h | 4 +- include/net/tcp.h | 4 +- net/dccp/dccp.h | 4 +- net/dccp/ipv4.c | 4 +- net/dccp/ipv6.c | 7 ++- net/dccp/minisocks.c | 2 +- net/ipv4/syncookies.c | 2 +- net/ipv4/tcp_fastopen.c | 2 +- net/ipv4/tcp_ipv4.c | 8 ++- net/ipv4/tcp_minisocks.c | 2 +- net/ipv6/tcp_ipv6.c | 98 +++++++++++++----------------- net/mptcp/subflow.c | 6 +- 12 files changed, 74 insertions(+), 69 deletions(-)
include/net/inet_connection_sock.h +3 -1
@@ -41,7 +41,9 @@ struct inet_connection_sock_af_ops {struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req); + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk));u16 net_header_len;u16 net_frag_header_len;u16 sockaddr_len;
include/net/tcp.h +3 -1
@@ -438,7 +438,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req); + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk));int tcp_v4_do_rcv (struct sock *sk,struct sk_buff *skb);int tcp_v4_connect (struct sock *sk,struct sockaddr *uaddr,int addr_len);int tcp_connect (struct sock *sk);
net/dccp/dccp.h +3 -1
@@ -272,7 +272,9 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk, struct sk_buff *skstruct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req); + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk));struct sock *dccp_check_req (struct sock *sk,struct sk_buff *skb,struct request_sock *req);
net/dccp/ipv4.c +3 -1
@@ -397,7 +397,9 @@ struct sock *dccp_v4_request_recv_sock(const struct sock *sk,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct inet_request_sock *ireq;struct inet_sock *newinet;
net/dccp/ipv6.c +5 -2
@@ -403,7 +403,9 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct inet_request_sock *ireq = inet_rsk(req);struct ipv6_pinfo *newnp;
@@ -418,7 +420,8 @@ static struct sock *dccp_v6_request_recv_sock(const struct sock *sk,* v6 mapped */ newsk =dccp_v4_request_recv_sock (sk, skb, req, dst, - req_unhash, own_req); + req_unhash, own_req, + opt_child_init);if (newsk ==NULL )return NULL ;
net/dccp/minisocks.c +1 -1
@@ -192,7 +192,7 @@ struct sock *dccp_check_req(struct sock *sk, struct sk_buff *skb, goto drop; child =inet_csk (sk)->icsk_af_ops->syn_recv_sock (sk, skb, req,NULL , - req, &own_req); + req, &own_req,NULL );if (child) { child =inet_csk_complete_hashdance (sk, child, req, own_req); goto out;
net/ipv4/syncookies.c +1 -1
@@ -201,7 +201,7 @@ struct sock *tcp_get_cookie_sock(struct sock *sk, struct sk_buff *skb,bool own_req; child = icsk->icsk_af_ops->syn_recv_sock (sk, skb, req, dst, -NULL , &own_req); +NULL , &own_req,NULL );if (child) {refcount_set (&req->rsk_refcnt,1 );tcp_sk (child)->tsoffset = tsoff;
net/ipv4/tcp_fastopen.c +1 -1
@@ -262,7 +262,7 @@ static struct sock *tcp_fastopen_create_child(struct sock *sk,bool own_req; child =inet_csk (sk)->icsk_af_ops->syn_recv_sock (sk, skb, req,NULL , -NULL , &own_req); +NULL , &own_req,NULL );if (!child)return NULL ;
net/ipv4/tcp_ipv4.c +7 -1
@@ -1535,7 +1535,9 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct inet_request_sock *ireq;bool found_dup_sk = false;
@@ -1591,6 +1593,10 @@ struct sock *tcp_v4_syn_recv_sock(const struct sock *sk, struct sk_buff *skb, }sk_setup_caps (newsk, dst); +#if IS_ENABLED (CONFIG_IPV6 ) +if (opt_child_init) +opt_child_init (newsk, sk); +#endif tcp_ca_openreq_child (newsk, dst);tcp_sync_mss (newsk,dst_mtu (dst));
net/ipv4/tcp_minisocks.c +1 -1
@@ -770,7 +770,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,* socket is created, wait for troubles. */ child =inet_csk (sk)->icsk_af_ops->syn_recv_sock (sk, skb, req,NULL , - req, &own_req); + req, &own_req,NULL );if (!child) goto listen_overflow;
net/ipv6/tcp_ipv6.c +42 -56
114 lines not on this page · raw message
net/mptcp/subflow.c +4 -2
@@ -532,7 +532,9 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk,struct request_sock *req, struct dst_entry *dst, struct request_sock *req_unhash, - bool *own_req) + bool *own_req, + void (*opt_child_init)(struct sock *newsk, + const struct sock *sk)) { struct mptcp_subflow_context *listener = mptcp_subflow_ctx(sk);struct mptcp_subflow_request_sock *subflow_req;
@@ -582,7 +584,7 @@ static struct sock *subflow_syn_recv_sock(const struct sock *sk, create_child: child = listener->icsk_af_ops->syn_recv_sock (sk, skb, req, dst, - req_unhash, own_req); + req_unhash, own_req, opt_child_init);if (child && *own_req) {struct mptcp_subflow_context *ctx =mptcp_subflow_ctx (child);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 204/798 selinux: avoid implicit conversions in services code
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Christian Göttsche <[email protected]>
commit c50e125d057152bc68dfd5669b73611343653eb7 upstream.
Use u32 as the output parameter type in security_get_classes() and security_get_permissions(), based on the type of the symtab nprim member.
Declare the read-only class string parameter ofsecurity_get_permissions() const.
Avoid several implicit conversions by using the identical type for the destination.
Use the type identical to the source for local variables.
--- security/selinux/include/security.h | 4 ++-- security/selinux/selinuxfs.c | 7 ++++--- security/selinux/ss/services.c | 23 ++++++++++++----------- 3 files changed, 18 insertions(+), 16 deletions(-)
security/selinux/include/security.h +2 -2
@@ -374,9 +374,9 @@ int security_net_peersid_resolve(struct selinux_state *state, u32 *peer_sid);int security_get_classes (struct selinux_policy *policy, -char ***classes,int *nclasses); +char ***classes,u32 *nclasses);int security_get_permissions (struct selinux_policy *policy, -char *class,char ***perms,int *nperms); +char *class,char ***perms,u32 *nperms);int security_get_reject_unknown (struct selinux_state *state);int security_get_allow_unknown (struct selinux_state *state);
security/selinux/selinuxfs.c +4 -3
@@ -1867,7 +1867,8 @@ static int sel_make_perm_files(struct selinux_policy *newpolicy, char *objclass, int classvalue, struct dentry *dir) { - int i, rc, nperms; + u32 i, nperms; +int rc;char **perms; rc =security_get_permissions (newpolicy, objclass, &perms, &nperms);
@@ -1940,8 +1941,8 @@ static int sel_make_classes(struct selinux_policy *newpolicy,struct dentry *class_dir, unsigned long *last_class_ino) { - - int rc, nclasses, i; + u32 i, nclasses; +int rc;char **classes; rc =security_get_classes (newpolicy, &classes, &nclasses);
security/selinux/ss/services.c +12 -11
@@ -870,7 +870,7 @@ int security_bounded_transition(struct selinux_state *state,struct sidtab *sidtab;struct sidtab_entry *old_entry, *new_entry;struct type_datum *type; -int index; +u32 index;int rc;if (!selinux_initialized (state))
@@ -1535,7 +1535,7 @@ static int security_context_to_sid_core(struct selinux_state *state,return -ENOMEM ;if (!selinux_initialized (state)) { -int i; +u32 i;for (i =1 ; i <SECINITSID_NUM ; i++) {const char *s = initial_sid_to_string[i];
@@ -2869,7 +2869,6 @@ static inline int __security_genfs_sid(struct selinux_policy *policy, {struct policydb *policydb = &policy->policydb;struct sidtab *sidtab = policy->sidtab; -int len;u16 sclass;struct genfs *genfs;struct ocontext *c;
@@ -2891,7 +2890,7 @@ static inline int __security_genfs_sid(struct selinux_policy *policy,return -ENOENT ;for (c = genfs->head; c; c = c->next) { - len =strlen (c->u.name); +size_t len =strlen (c->u.name);if ((!c->v.sclass || sclass == c->v.sclass) && (strncmp (c->u.name, path, len) ==0 ))break ;
@@ -3382,7 +3381,7 @@ static int get_classes_callback(void *k, void *d, void *args) {struct class_datum *datum = d;char *name = k, **classes = args; -int value = datum->value -1 ; +u32 value = datum->value -1 ; classes[value] =kstrdup (name,GFP_ATOMIC );if (!classes[value])
@@ -3392,7 +3391,7 @@ static int get_classes_callback(void *k, void *d, void *args) }int security_get_classes (struct selinux_policy *policy, -char ***classes,int *nclasses) +char ***classes,u32 *nclasses) {struct policydb *policydb;int rc;
@@ -3408,7 +3407,8 @@ int security_get_classes(struct selinux_policy *policy, rc =hashtab_map (&policydb->p_classes.table, get_classes_callback, *classes);if (rc) { -int i; +u32 i; +for (i =0 ; i < *nclasses; i++)kfree ((*classes)[i]);kfree (*classes);
@@ -3422,7 +3422,7 @@ static int get_permissions_callback(void *k, void *d, void *args) {struct perm_datum *datum = d;char *name = k, **perms = args; -int value = datum->value -1 ; +u32 value = datum->value -1 ; perms[value] =kstrdup (name,GFP_ATOMIC );if (!perms[value])
@@ -3432,10 +3432,11 @@ static int get_permissions_callback(void *k, void *d, void *args) }int security_get_permissions (struct selinux_policy *policy, -char *class,char ***perms,int *nperms) +char *class,char ***perms,u32 *nperms) {struct policydb *policydb; -int rc, i; +u32 i; +int rc;struct class_datum *match; policydb = &policy->policydb;
@@ -3654,7 +3655,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule,/* Check to see if the rule contains any selinux fields */ int selinux_audit_rule_known (struct audit_krule *rule) { -int i; +u32 i;for (i =0 ; i < rule->field_count; i++) {struct audit_field *f = &rule->fields[i];
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 205/798 selinux: reject an unclaimed class value in security_get_classes()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 22b05fec62c0fe9864cfceb52f7d0f3a34d9b1dd upstream.
security_get_classes() sizes an array by p_classes.nprim and fills it at value - 1, so a class value the policy never defines leaves a NULL. sel_make_classes() passes every entry to sel_make_dir(), reaching the same d_alloc_name() dereference as the permission array. The class symbol table is allowed to be sparse (policydb_class_isvalid() exists to absorb that), but this getter builds its own array straight from the hash table and has no such predicate.
Fail the lookup when a value went unclaimed instead of handing out the NULL. Conforming policies define every class they declare and are unaffected.
--- security/selinux/ss/services.c | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-)
security/selinux/ss/services.c +19 -5
@@ -3394,6 +3394,7 @@ int security_get_classes(struct selinux_policy *policy, char ***classes, u32 *nclasses) { struct policydb *policydb; +u32 i;int rc; policydb = &policy->policydb;
@@ -3406,16 +3407,29 @@ int security_get_classes(struct selinux_policy *policy, rc =hashtab_map (&policydb->p_classes.table, get_classes_callback, *classes); -if (rc) { -u32 i; +if (rc) + goto err; -for (i =0 ; i < *nclasses; i++) -kfree ((*classes)[i]); -kfree (*classes); +/* +* The class symtab may be sparse, which policydb_class_isvalid() exists +* to absorb; the callback fills this array by value, so an unclaimed +* one leaves a NULL that sel_make_classes() hands to sel_make_dir(). +*/ +for (i =0 ; i < *nclasses; i++) { +if (!(*classes)[i]) { + rc = -EINVAL ; + goto err; + } } out:return rc; + +err: +for (i =0 ; i < *nclasses; i++) +kfree ((*classes)[i]); +kfree (*classes); +return rc; }static int get_permissions_callback (void *k,void *d,void *args)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 206/798 net: ntb_netdev: Fix TX busy and drop handling
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit 8aaa47351db0f93a5c5297fbafdfa8bc75e8ae49 upstream.
Currently, ntb_netdev returns NETDEV_TX_BUSY for every enqueue error. It also increments the drop and error counters while leaving the skb owned by the qdisc, and may return BUSY with the subqueue still awake. Retrying a permanent error cannot succeed either.
The unconditional BUSY return and premature accounting date back to the initial driver. The error-path queue stop was later removed without changing that return value. The current flow-control code includes a resource check, but ntb_netdev does not honor its result before enqueue.
Honor the resource check before enqueue. For -EAGAIN and -EBUSY, stop the subqueue, arm the existing reaper timer, and return BUSY without touching the skb. For other errors, free the skb, increment tx_dropped, and return NETDEV_TX_OK.
[den: adapt to the single-queue implementation, as 5.10.y lacks commit:
ee970634c777 ("net: ntb_netdev: Introduce per-queue context")]
Stable-dep-of: 873ce713fef5 ("NTB: ntb_transport: Fail TX enqueue when the QP link is down")
Stable-dep-of: a4f2387db6f1 ("NTB: ntb_transport: Reject oversized TX buffers")
--- drivers/net/ntb_netdev.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-)
drivers/net/ntb_netdev.c +19 -8
@@ -164,8 +164,10 @@ static int __ntb_netdev_maybe_stop_tx(struct net_device *netdev,static int ntb_netdev_maybe_stop_tx (struct net_device *ndev,struct ntb_transport_qp *qp,int size) { -if (netif_queue_stopped (ndev) || - (ntb_transport_tx_free_entry (qp) >= size)) +if (netif_queue_stopped (ndev)) +return -EBUSY ; + +if (ntb_transport_tx_free_entry (qp) >= size)return 0 ;return __ntb_netdev_maybe_stop_tx (ndev, qp, size);
@@ -208,21 +210,30 @@ static netdev_tx_t ntb_netdev_start_xmit(struct sk_buff *skb,struct ntb_netdev *dev =netdev_priv (ndev);int rc; -ntb_netdev_maybe_stop_tx (ndev, dev->qp, tx_stop); +if (unlikely (ntb_netdev_maybe_stop_tx (ndev, dev->qp, tx_stop))) +return NETDEV_TX_BUSY ; rc =ntb_transport_tx_enqueue (dev->qp, skb, skb->data, skb->len); -if (rc) - goto err; +if (rc) { +if (rc == -EAGAIN || rc == -EBUSY ) { +netif_stop_queue (ndev); +mod_timer (&dev->tx_timer, + jiffies +usecs_to_jiffies (tx_time)); +return NETDEV_TX_BUSY ; + } + + goto drop; + }/* check for next submit */ ntb_netdev_maybe_stop_tx (ndev, dev->qp, tx_stop);return NETDEV_TX_OK ; -err: +drop: +dev_kfree_skb_any (skb); ndev->stats.tx_dropped++; - ndev->stats.tx_errors++; -return NETDEV_TX_BUSY ; +return NETDEV_TX_OK ; }static void ntb_netdev_tx_timer (struct timer_list *t)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 207/798 drm/vmwgfx: drop dma_buf reference on foreign-fd prime import
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zack Rusin <[email protected]>
commit f739416dc555fa205a785e5135d73fa39b26f35d upstream.
ttm_prime_fd_to_handle() returns -ENOSYS when the imported fd's dma_buf->ops do not match the ttm_object_device's ops, but does so without releasing the reference acquired by dma_buf_get(). Any unprivileged renderD client passing a non-vmwgfx prime fd through the DRM_VMW_GB_SURFACE_REF{,_EXT} path leaks one dma_buf reference per call and indefinitely pins the foreign exporter's GEM resources.
Funnel the error path through the existing dma_buf_put() so the reference is always dropped.
--- drivers/gpu/drm/vmwgfx/ttm_object.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/gpu/drm/vmwgfx/ttm_object.c +5 -2
@@ -658,14 +658,17 @@ int ttm_prime_fd_to_handle(struct ttm_object_file *tfile,if (IS_ERR (dma_buf))return PTR_ERR (dma_buf); -if (dma_buf->ops != &tdev->ops) -return -ENOSYS ; +if (dma_buf->ops != &tdev->ops) { + ret = -ENOSYS ; + goto out; + } prime = (struct ttm_prime_object *) dma_buf->priv; base = &prime->base; *handle = base->handle; ret =ttm_ref_object_add (tfile, base,TTM_REF_USAGE ,NULL , false); +out:dma_buf_put (dma_buf);return ret;
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 208/798 net/smc: fix potential panic dues to unprotected smc_llc_srv_add_link()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: D. Wythe <[email protected]>
commit e40b801b3603a8f90b46acbacdea3505c27f01c0 upstream.
There is a certain chance to trigger the following panic:
PID: 5900 TASK: ffff88c1c8af4100 CPU: 1 COMMAND: "kworker/1:48"
#0 [ffff9456c1cc79a0] machine_kexec at ffffffff870665b7 #1 [ffff9456c1cc79f0] __crash_kexec at ffffffff871b4c7a #2 [ffff9456c1cc7ab0] crash_kexec at ffffffff871b5b60 #3 [ffff9456c1cc7ac0] oops_end at ffffffff87026ce7 #4 [ffff9456c1cc7ae0] page_fault_oops at ffffffff87075715 #5 [ffff9456c1cc7b58] exc_page_fault at ffffffff87ad0654 #6 [ffff9456c1cc7b80] asm_exc_page_fault at ffffffff87c00b62
[exception RIP: ib_alloc_mr+19]
RIP: ffffffffc0c9cce3 RSP: ffff9456c1cc7c38 RFLAGS: 00010202
RAX: 0000000000000000 RBX: 0000000000000002 RCX: 0000000000000004
RDX: 0000000000000010 RSI: 0000000000000000 RDI: 0000000000000000
RBP: ffff88c1ea281d00 R8: 000000020a34ffff R9: ffff88c1350bbb20
R10: 0000000000000000 R11: 0000000000000001 R12: 0000000000000000
R13: 0000000000000010 R14: ffff88c1ab040a50 R15: ffff88c1ea281d00
ORIG_RAX: ffffffffffffffff CS: 0010 SS: 0018 #7 [ffff9456c1cc7c60] smc_ib_get_memory_region at ffffffffc0aff6df [smc] #8 [ffff9456c1cc7c88] smcr_buf_map_link at ffffffffc0b0278c [smc] #9 [ffff9456c1cc7ce0] __smc_buf_create at ffffffffc0b03586 [smc]
The reason here is that when the server tries to create a second link, smc_llc_srv_add_link() has no protection and may add a new link to link group. This breaks the security environment protected by llc_conf_mutex.
[Denis Arefev: adapted for 5.10: smc_llc_srv_add_link() has no req_qentry argument here, as SMC-Rv2 REQ_ADD_LINK support is not present in 5.10]
--- net/smc/af_smc.c | 2 ++ 1 file changed, 2 insertions(+)
net/smc/af_smc.c +2 -0
@@ -1303,8 +1303,10 @@ static int smcr_serv_conf_first_link(struct smc_sock *smc)smc_llc_link_active (link);smcr_lgr_set_type (link->lgr,SMC_LGR_SINGLE ); +mutex_lock (&link->lgr->llc_conf_mutex);/* initial contact - try to establish second link */ smc_llc_srv_add_link (link); +mutex_unlock (&link->lgr->llc_conf_mutex);return 0 ; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 209/798 tracing/mmiotrace: Remove reference to unused per CPU data pointer
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Steven Rostedt <[email protected]>
commit 6936298393d8d8bc3cec6b704f6a774162cf9bd3 upstream.
The mmiotracer referenced the per CPU array_buffer->data descriptor but never actually used it. Remove the references to it.
--- kernel/trace/trace_mmiotrace.c | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-)
kernel/trace/trace_mmiotrace.c +2 -10
@@ -294,7 +294,6 @@ __init static int init_mmio_trace(void)device_initcall (init_mmio_trace);static void __trace_mmiotrace_rw (struct trace_array *tr, -struct trace_array_cpu *data,struct mmiotrace_rw *rw) {struct trace_event_call *call = &event_mmiotrace_rw;
@@ -319,12 +318,10 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,void mmio_trace_rw (struct mmiotrace_rw *rw) {struct trace_array *tr = mmio_trace_array; -struct trace_array_cpu *data =per_cpu_ptr (tr->array_buffer.data,smp_processor_id ()); -__trace_mmiotrace_rw (tr, data, rw); +__trace_mmiotrace_rw (tr, rw); }static void __trace_mmiotrace_map (struct trace_array *tr, -struct trace_array_cpu *data,struct mmiotrace_map *map) {struct trace_event_call *call = &event_mmiotrace_map;
@@ -349,12 +346,7 @@ static void __trace_mmiotrace_map(struct trace_array *tr,void mmio_trace_mapping (struct mmiotrace_map *map) {struct trace_array *tr = mmio_trace_array; -struct trace_array_cpu *data; - -preempt_disable (); - data =per_cpu_ptr (tr->array_buffer.data,smp_processor_id ()); -__trace_mmiotrace_map (tr, data, map); -preempt_enable (); +__trace_mmiotrace_map (tr, map); }int mmio_trace_printk (const char *fmt,va_list args)
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 210/798 tracing/mmiotrace: Add NULL check for mmio_trace_array in logging functions
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Masami Hiramatsu (Google) <[email protected]>
commit 12b80cdbc54cf615b4717a4e8180063408091ea2 upstream.
mmio_trace_rw() and mmio_trace_mapping() retrieve mmio_trace_array into tr and pass it to __trace_mmiotrace_rw() and __trace_mmiotrace_map(). If these functions are invoked while mmio_trace_array is NULL (e.g. before initialization or after disabled), accessing tr->array_buffer.buffer will result in a NULL pointer dereference crash.
Fix this by adding an explicit NULL check for tr at the beginning of __trace_mmiotrace_rw() and __trace_mmiotrace_map().
--- kernel/trace/trace_mmiotrace.c | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-)
kernel/trace/trace_mmiotrace.c +10 -2
@@ -297,11 +297,15 @@ static void __trace_mmiotrace_rw(struct trace_array *tr, struct mmiotrace_rw *rw) {struct trace_event_call *call = &event_mmiotrace_rw; -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_rw *entry;int pc =preempt_count (); +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_RW ,sizeof (*entry),0 , pc);if (!event) {
@@ -325,11 +329,15 @@ static void __trace_mmiotrace_map(struct trace_array *tr, struct mmiotrace_map *map) {struct trace_event_call *call = &event_mmiotrace_map; -struct trace_buffer *buffer = tr->array_buffer.buffer; +struct trace_buffer *buffer;struct ring_buffer_event *event;struct trace_mmiotrace_map *entry;int pc =preempt_count (); +if (!tr) +return ; + + buffer = tr->array_buffer.buffer; event =trace_buffer_lock_reserve (buffer,TRACE_MMIO_MAP ,sizeof (*entry),0 , pc);if (!event) {
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 211/798 scsi: core: Fill in DMA padding bytes in scsi_alloc_sgtables()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Petr Vaganov <[email protected]>
commit 626147717bea776b61ed3631d2c26283760c4cc4 upstream.
During fuzz testing, the following issue was discovered:
BUG: KMSAN: uninit-value in __dma_map_sg_attrs+0x217/0x310 __dma_map_sg_attrs+0x217/0x310 dma_map_sg_attrs+0x4a/0x70 ata_qc_issue+0x9f8/0x1420 __ata_scsi_queuecmd+0x1657/0x1740 ata_scsi_queuecmd+0x79a/0x920 scsi_queue_rq+0x4472/0x4f40 blk_mq_dispatch_rq_list+0x1cca/0x3ee0 __blk_mq_sched_dispatch_requests+0x458/0x630 blk_mq_sched_dispatch_requests+0x15b/0x340 __blk_mq_run_hw_queue+0xe5/0x250 __blk_mq_delay_run_hw_queue+0x138/0x780 blk_mq_run_hw_queue+0x4bb/0x7e0 blk_mq_sched_insert_request+0x2a7/0x4c0 blk_execute_rq+0x497/0x8a0 sg_io+0xbe0/0xe20 scsi_ioctl+0x2b36/0x3c60 sr_block_ioctl+0x319/0x440 blkdev_ioctl+0x80f/0xd70 __se_sys_ioctl+0x219/0x420 __x64_sys_ioctl+0x93/0xe0 x64_sys_call+0x1d6c/0x3ad0 do_syscall_64+0x4c/0xa0 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
Uninit was created at:
__alloc_pages+0x5c0/0xc80 alloc_pages+0xe0e/0x1050 blk_rq_map_user_iov+0x2b77/0x6100 blk_rq_map_user_io+0x2fa/0x4d0 sg_io+0xad6/0xe20 scsi_ioctl+0x2b36/0x3c60 sr_block_ioctl+0x319/0x440 blkdev_ioctl+0x80f/0xd70 __se_sys_ioctl+0x219/0x420 __x64_sys_ioctl+0x93/0xe0 x64_sys_call+0x1d6c/0x3ad0 do_syscall_64+0x4c/0xa0 entry_SYSCALL_64_after_hwframe+0x6e/0xd8
Bytes 14-15 of 16 are uninitialized
Memory access of size 16 starts at ffff88800cbdb000
When processing the last unaligned element of the scatterlist, it is supplemented with missing bytes in the amount of pad_len. These bytes remain uninitialized, which leads to a problem.
Extend last_sg->length by pad_len first, then use sg_zero_buffer() to zero those pad_len bytes. sg_zero_buffer() uses sg_miter internally, which correctly handles sg entries spanning multiple pages and padding that crosses a page boundary.
Found by Linux Verification Center (linuxtesting.org) with Syzkaller.
--- drivers/scsi/scsi_lib.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/scsi/scsi_lib.c +2 -0
@@ -1050,8 +1050,10 @@ blk_status_t scsi_alloc_sgtables(struct scsi_cmnd *cmd)if (blk_rq_bytes (rq) & rq->q->dma_pad_mask) {unsigned int pad_len = (rq->q->dma_pad_mask & ~blk_rq_bytes (rq)) +1 ; +unsigned int data_len = last_sg->length; last_sg->length += pad_len; +sg_zero_buffer (last_sg,1 , pad_len, data_len); cmd->extra_len += pad_len; }
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 212/798 espintcp: remove encap socket caching to avoid reference leak
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sabrina Dubroca <[email protected]>
[ Upstream commit 028363685bd0b7a19b4a820f82dd905b1dc83999 ]
The current scheme for caching the encap socket can lead to reference leaks when we try to delete the netns.
The reference chain is: xfrm_state -> enacp_sk -> netns
Since the encap socket is a userspace socket, it holds a reference on the netns. If we delete the espintcp state (through flush or individual delete) before removing the netns, the reference on the socket is dropped and the netns is correctly deleted. Otherwise, the netns may not be reachable anymore (if all processes within the ns have terminated), so we cannot delete the xfrm state to drop its reference on the socket.
This patch results in a small (~2% in my tests) performance regression.
A GC-type mechanism could be added for the socket cache, to clear references if the state hasn't been used "recently", but it's a lot more complex than just not caching the socket.
--- include/net/xfrm.h | 1 - net/ipv4/esp4.c | 49 ++++--------------------------------------- net/ipv6/esp6.c | 49 ++++--------------------------------------- net/xfrm/xfrm_state.c | 3 --- 4 files changed, 8 insertions(+), 94 deletions(-)
include/net/xfrm.h +0 -1
@@ -206,7 +206,6 @@ struct xfrm_state {/* Data for encapsulator */ struct xfrm_encap_tmpl *encap; -struct sock __rcu *encap_sk;/* Data for care-of address */ xfrm_address_t *coaddr;
net/ipv4/esp4.c +4 -45
82 lines not on this page · raw message
net/ipv6/esp6.c +4 -45
82 lines not on this page · raw message
net/xfrm/xfrm_state.c +0 -3
@@ -667,9 +667,6 @@ int __xfrm_state_delete(struct xfrm_state *x) net->xfrm.state_num--;spin_unlock (&net->xfrm.xfrm_state_lock); -if (x->encap_sk) -sock_put (rcu_dereference_raw (x->encap_sk)); -xfrm_dev_state_delete (x);xfrm_state_delete_tunnel (x);
Signature · 1 line
2.53.0
Greg Kroah-Hartman
maintainerPATCH 213/798 usb: image: mdc800: change kmalloc() to kzalloc()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Griffin Kroah-Hartman <[email protected]>
commit 2430eb81e44111b30eeb5273bbcf8b24ca517ef9 upstream.
Change the kmalloc() calls in usb_mdc800_init() for irq_urb_buffer and download_urb_buffer to kzalloc(), avoiding potential stack leaks if a shorter message is received in mdc800_usb_irq() and mdc800_usb_download_notify()
--- drivers/usb/image/mdc800.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/usb/image/mdc800.c +2 -2
@@ -1001,13 +1001,13 @@ static int __init usb_mdc800_init (void) mdc800->downloaded =0 ; mdc800->written =0 ; - mdc800->irq_urb_buffer=kmalloc (8 ,GFP_KERNEL ); + mdc800->irq_urb_buffer=kzalloc (8 ,GFP_KERNEL );if (!mdc800->irq_urb_buffer) goto cleanup_on_fail; mdc800->write_urb_buffer=kmalloc (8 ,GFP_KERNEL );if (!mdc800->write_urb_buffer) goto cleanup_on_fail; - mdc800->download_urb_buffer=kmalloc (64 ,GFP_KERNEL ); + mdc800->download_urb_buffer=kzalloc (64 ,GFP_KERNEL );if (!mdc800->download_urb_buffer) goto cleanup_on_fail;
Greg Kroah-Hartman
maintainerPATCH 214/798 ALSA: usb-audio: fix OOB write in snd_usbmidi_us122l_output()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: HyeongJun An <[email protected]>
commit e4637ce34607f1733a34a57294966d26b263e626 upstream.
The snd_usbmidi_us122l_output() picks a count of 2 on anything slower than high speed and never relates it to ep->max_transfer. The URB buffer holds exactly max_transfer bytes, so a device declaring a one byte bulk endpoint takes two bytes from snd_rawmidi_transmit(), and the memset that pads the rest computes 1 - 2 in int and wraps to SIZE_MAX.
Only 0x800e and 0x800f are pinned to nine bytes. The US-122MKII at 0x0644:0x8021 falls to the default and takes usb_maxpacket(), which the USB core only clamps downward.
The akai and novation output ops in this file were given the same guard recently. Do the same here.
--- sound/usb/midi.c | 2 ++ 1 file changed, 2 insertions(+)
sound/usb/midi.c +2 -0
@@ -990,6 +990,8 @@ static void snd_usbmidi_us122l_output(stdefault : count =2 ; } +if (ep->max_transfer < count) +return ; count =snd_rawmidi_transmit (ep->ports[0 ].substream, urb->transfer_buffer, count);
Greg Kroah-Hartman
maintainerPATCH 215/798 media: usbtv: keep device alive while ALSA card exists
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shuangpeng Bai <[email protected]>
commit fc530fe168bb2b745a93f553ad21fc25fd9cba3d upstream.
The ALSA PCM callbacks store the driver state in pcm->private_data. An open PCM file can outlive USB disconnect because usbtv_audio_free() uses snd_card_free_when_closed(). The disconnect path can then drop the V4L2 device reference and free struct usbtv before ALSA releases the substream, so a later close dereferences freed memory in snd_usbtv_pcm_close().
Take a V4L2 device reference for the ALSA card and drop it from the card private_free callback. This keeps struct usbtv valid until ALSA has closed the remaining files and freed the card.
--- drivers/media/usb/usbtv/usbtv-audio.c | 11 +++++++++++ 1 file changed, 11 insertions(+)
drivers/media/usb/usbtv/usbtv-audio.c +11 -0
@@ -317,6 +317,13 @@ static const struct snd_pcm_ops snd_usbt .pointer = snd_usbtv_pointer, }; +static void usbtv_audio_card_free (struct snd_card *card) +{ +struct usbtv *usbtv = card->private_data; + +v4l2_device_put (&usbtv->v4l2_dev); +} +int usbtv_audio_init (struct usbtv *usbtv) {int rv;
@@ -331,6 +338,10 @@ int usbtv_audio_init(struct usbtv *usbtvif (rv <0 )return rv; +v4l2_device_get (&usbtv->v4l2_dev); + card->private_data = usbtv; + card->private_free = usbtv_audio_card_free; +strscpy (card->driver, usbtv->dev->driver->name,sizeof (card->driver));strscpy (card->shortname,"usbtv" ,sizeof (card->shortname)); snprintf(card->longname, sizeof(card->longname),
Greg Kroah-Hartman
maintainerPATCH 216/798 usb-storage: ene_ub6250: fix race between scan work and probe
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Liu Qi <[email protected]>
commit 445fc368c6bc73eff0aeb3818cf5f355facfbb16 upstream.
ene_ub6250_probe() calls usb_stor_probe2(), which starts the usb-storage infrastructure and schedules the delayed scan work. The driver then calls ene_get_card_type(), which sends an ENE command through ene_send_scsi_cmd() and the usb-storage bulk transfer helpers.
Both the delayed scan work, through usb_stor_Bulk_max_lun(), and ene_get_card_type() use us->current_urb. The scan work serializes this access with us->dev_mutex, but the ENE card-type probe does not. If the scan work runs while ene_get_card_type() is still using us->current_urb, usb_submit_urb() warns that the URB is already active.
Serialize ene_get_card_type() with us->dev_mutex, matching the locking used by the scan path.
--- drivers/usb/storage/ene_ub6250.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/usb/storage/ene_ub6250.c +2 -0
@@ -2357,7 +2357,9 @@ static int ene_ub6250_probe(struct usb_ireturn result;/* probe card type */ +mutex_lock (&us->dev_mutex); result =ene_get_card_type (us,REG_CARD_STATUS , info->bbuf); +mutex_unlock (&us->dev_mutex);if (result !=USB_STOR_XFER_GOOD ) {usb_stor_disconnect (intf);return USB_STOR_TRANSPORT_ERROR ;
Greg Kroah-Hartman
maintainerPATCH 217/798 usb: f_mass_storage: Bump local buffer size in fsg_common_create_luns()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
commit 9f6f095beec82a80daa666a3b2186a5b95841e9a upstream.
GCC (Debian 14.2.0-19) is not happy about the buffer size:
drivers/usb/gadget/function/f_mass_storage.c:2970:48: error: ‘%d’ directive output may be truncated writing between 1 and 9 bytes into a region of size 5 [-Werror=format-truncation=]
Bump the size to get it enough for all possible values.
Note, although cfg->nluns is limited to FSG_MAX_LUNS (16), the compiler doesn't realize this and complains about the buffer size.
Also note, the existing comment is wrong as size 8 for the whole buffer doesn't cover 100 mil numbers, hence drop it altogether.
--- drivers/usb/gadget/function/f_mass_storage.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_mass_storage.c +1 -1
@@ -2840,7 +2840,7 @@ EXPORT_SYMBOL_GPL(fsg_common_create_lun)int fsg_common_create_luns (struct fsg_common *common,struct fsg_config *cfg) { -char buf[8 ];/* enough for 100000000 different numbers, decimal */ +char buf[14 ];int i, rc;fsg_common_remove_luns (common);
Greg Kroah-Hartman
maintainerPATCH 218/798 usb: typec: ucsi: displayport: Fix OOB altmode array index
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jameson Thies <[email protected]>
commit 04cec690b1fd9d1c4c314b91a10d8c68a3acfe18 upstream.
The UCSI displayport driver indexes the connector's port altmode array with the GET_CURRENT_CAM response after checking it is not 0xff. The port altmode array is UCSI_MAX_ALTMODES elements long. If the PPM returns an invalid GET_CURRENT_CAM response above UCSI_MAX_ALTMODES and not equal to 0xff, the kernel may crash with an array index OOB error.
Update the UCSI displayport driver to verify the current cam is less than UCSI_MAX_ALTMODES before accessing the port altmode array.
--- drivers/usb/typec/ucsi/displayport.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/typec/ucsi/displayport.c +1 -1
@@ -72,7 +72,7 @@ static int ucsi_displayport_enter(struct cur =0xff ; } -if (cur !=0xff ) { +if (cur <UCSI_MAX_ALTMODES ) { ret = dp->con->port_altmode[cur] == alt ?0 : -EBUSY ; goto err_unlock; }
Greg Kroah-Hartman
maintainerPATCH 219/798 USB: gadget: fix NULL pointer dereference in gadget_dev_ioctl()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Lovekesh Solanki <[email protected]>
commit dd0eed9e165b1a6292f49e622e3dd0b7d99b106d upstream.
gadget_dev_ioctl() reads dev->gadget before acquiring dev->lock, but dev->state is checked after acquiring the lock. Therefore a concurrent bind can change the device state between these operations, which can leave ioctl with a stale NULL gadget pointer and causing a NULL pointer dereference at gadget->ops->ioctl.
Read dev->gadget while holding dev->lock so that the gadget pointer and device state are sampled consistently.
--- drivers/usb/gadget/legacy/inode.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/usb/gadget/legacy/inode.c +2 -1
@@ -1249,10 +1249,11 @@ out:static long dev_ioctl (struct file *fd,unsigned code,unsigned long value) {struct dev_data *dev = fd->private_data; -struct usb_gadget *gadget = dev->gadget; +struct usb_gadget *gadget;long ret = -ENOTTY ;spin_lock_irq (&dev->lock); + gadget = dev->gadget;if (dev->state ==STATE_DEV_OPENED || dev->state ==STATE_DEV_UNBOUND ) {/* Not bound to a UDC */
Greg Kroah-Hartman
maintainerPATCH 220/798 usb: gadget: fix null pointer dereference in usb_put_function_instance()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Jeffin Philip <[email protected]>
commit 6e74ac5c596fd246e37eadfc354567179ccbe9aa upstream.
usb_put_function_instance() attempts to dereference fd inside fi struct to get mod in uvc_alloc_inst() error path. However, fd is not allocated until later in try_get_usb_function_instance() after allocating fi in uvc_alloc_inst() and thus guranteed to be null in error path. Fix this by adding a null check for fi->fd that returns if fd is null.
--- drivers/usb/gadget/functions.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/functions.c +1 -1
@@ -70,7 +70,7 @@ void usb_put_function_instance(struct us {struct module *mod; -if (!fi) +if (!fi || !fi->fd)return ; mod = fi->fd->mod;
Greg Kroah-Hartman
maintainerPATCH 221/798 staging: rtl8723bs: fix OOB read in rtw_action_frame_parse()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Muhammad Bilal <[email protected]>
commit ff917923f4fb9c83717ba135ee47d7e4c1567bb7 upstream.
rtw_action_frame_parse() takes a frame_len parameter but never actually checks it before indexing into the frame body:
const u8 *frame_body = frame + sizeof(struct ieee80211_hdr_3addr); ... c = frame_body[0]; ... a = frame_body[1];
frame_body already points 24 bytes (sizeof(struct ieee80211_hdr_3addr)) into frame, so reading frame_body[0] and frame_body[1] requires frame_len >= 26. A management action frame shorter than that (e.g. exactly 24 bytes, the minimum a malicious peer can send) causes a 1-2 byte out-of-bounds read.
This is reachable from rtw_cfg80211_monitor_if_xmit_entry() and cfg80211_rtw_mgmt_tx() in ioctl_cfg80211.c, both of which pass attacker/user-influenced frame buffers and lengths straight through.
Add the missing length check before frame_body is dereferenced.
--- drivers/staging/rtl8723bs/core/rtw_ieee80211.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/staging/rtl8723bs/core/rtw_ieee80211.c +3 -0
@@ -1291,6 +1291,9 @@ int rtw_action_frame_parse(const u8 *frau8 c;u8 a =ACT_PUBLIC_MAX ; +if (frame_len <sizeof (struct ieee80211_hdr_3addr ) +2 ) +return false; + fc =le16_to_cpu (((struct ieee80211_hdr_3addr *)frame)->frame_control); if ((fc & (IEEE80211_FCTL_FTYPE|IEEE80211_FCTL_STYPE))
Greg Kroah-Hartman
maintainerPATCH 222/798 thermal/drivers/imx: Disable clock on runtime resume failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit bcc6d886e5006a4656901d2d7fb6a215c96068a0 upstream.
imx_thermal_runtime_resume() enables the thermal clock before powering up the sensor and enabling measurements.
If either regmap_write() fails, the function returns with the clock still enabled. This leaves the clock enable count unbalanced after a failed runtime resume.
Disable the clock on those failure paths before returning the error.
--- drivers/thermal/imx_thermal.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/thermal/imx_thermal.c +7 -2
@@ -897,12 +897,12 @@ static int __maybe_unused imx_thermal_ru ret =regmap_write (map, socdata->sensor_ctrl +REG_CLR , socdata->power_down_mask);if (ret) -return ret; + goto disable_clk; ret =regmap_write (map, socdata->sensor_ctrl +REG_SET , socdata->measure_temp_mask);if (ret) -return ret; + goto disable_clk;/* * According to the temp sensor designers, it may require up to ~17us
@@ -911,6 +911,11 @@ static int __maybe_unused imx_thermal_ruusleep_range (20 ,50 );return 0 ; + +disable_clk: +clk_disable_unprepare (data->thermal_clk); + +return ret; }static const struct dev_pm_ops imx_thermal_pm_ops = {
Greg Kroah-Hartman
maintainerPATCH 223/798 thermal/drivers/qoriq: Disable clock on resume failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Can Peng <[email protected]>
commit fcbf9964b67a6d6704c50ed28daa24c3b164f01c upstream.
qoriq_tmu_resume() enables the TMU clock before clearing the power-down bit and enabling monitoring.
If either register update fails, the function returns with the clock still enabled. This leaves the clock enable count unbalanced after a failed resume.
Disable the clock on those failure paths before returning the error.
--- drivers/thermal/qoriq_thermal.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
drivers/thermal/qoriq_thermal.c +11 -2
@@ -369,11 +369,20 @@ static int __maybe_unused qoriq_tmu_resuif (data->ver >TMU_VER1 ) { ret =regmap_clear_bits (data->regmap,REGS_TMR ,TMR_CMD );if (ret) -return ret; + goto disable_clk; }/* Enable monitoring */ -return regmap_update_bits (data->regmap,REGS_TMR ,TMR_ME ,TMR_ME ); + ret =regmap_update_bits (data->regmap,REGS_TMR ,TMR_ME ,TMR_ME ); +if (ret) + goto disable_clk; + +return 0 ; + +disable_clk: +clk_disable_unprepare (data->clk); + +return ret; } static SIMPLE_DEV_PM_OPS(qoriq_tmu_pm_ops,
Greg Kroah-Hartman
maintainerPATCH 224/798 scsi: target: iscsi: Reserve a terminator byte for the login payload
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sujal Tuladhar <[email protected]>
commit f4825922d2fb371e2b969697d792077f1b62b62c upstream.
iscsi_target_check_login_request() rejects a login PDU whose DataSegmentLength exceeds MAX_KEY_VALUE_PAIRS, but the test is '>' and login->req_buf is allocated with exactly MAX_KEY_VALUE_PAIRS bytes. Since iscsit_get_login_rx() receives payload_length + padding bytes, where
padding = ((-payload_length) & 3);
any payload_length from 8189 to 8192 fills the whole 8192 byte buffer. The write stays in bounds, but no byte is left for a NUL terminator.
The buffer is subsequently consumed as a C string. In the CHAP path chap_check_algorithm() calls kstrdup(a_str), and extract_param() calls strstr(in_buf, pattern) followed by strlen_semi(), none of which take a length. convert_null_to_semi() additionally rewrites every embedded NUL to ';', so even a payload made of well formed NUL separated key=value records is left without a terminator. These walk past the end of the object into adjacent slab memory. It is reachable by an unauthenticated initiator against a portal configured for CHAP; when authentication is not required iscsi_login_zero_tsih_s2() rewrites AuthMethod to None and the CHAP path is never entered.
Allocate one extra byte. kzalloc() zeroes it and nothing ever writes to it, as every writer copies to offset 0 for at most MAX_KEY_VALUE_PAIRS bytes, so the buffer is always terminated.
--- drivers/target/iscsi/iscsi_target_login.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/target/iscsi/iscsi_target_login.c +1 -1
@@ -48,7 +48,7 @@ static struct iscsi_login *iscsi_login_i login->conn = conn; login->first_request =1 ; - login->req_buf =kzalloc (MAX_KEY_VALUE_PAIRS ,GFP_KERNEL ); + login->req_buf =kzalloc (MAX_KEY_VALUE_PAIRS +1 ,GFP_KERNEL );if (!login->req_buf) {pr_err ("Unable to allocate memory for response buffer.\n" ); goto out_login;
Greg Kroah-Hartman
maintainerPATCH 225/798 scsi: pm8001: Use rollback index when freeing MSI-X vectors
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 3f92a64545165bdbb36dee8fa35626b295463313 upstream.
pm8001_request_msix() unwinds previously registered handlers with free_irq() when request_irq() fails. The rollback loop uses the failing index i for every iteration instead of the already registered vector index j.
That passes the wrong IRQ/dev_id pair to free_irq() and leaves the earlier handlers installed. Use j for both pci_irq_vector() and the matching irq_vector entry in the rollback loop.
--- drivers/scsi/pm8001/pm8001_init.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/scsi/pm8001/pm8001_init.c +2 -2
@@ -971,8 +971,8 @@ static u32 pm8001_request_msix(struct pm &(pm8001_ha->irq_vector[i]));if (rc) {for (j =0 ; j < i; j++) { -free_irq (pci_irq_vector (pm8001_ha->pdev, i), - &(pm8001_ha->irq_vector[i])); +free_irq (pci_irq_vector (pm8001_ha->pdev, j), + &pm8001_ha->irq_vector[j]); }pci_free_irq_vectors (pm8001_ha->pdev);break ;
Greg Kroah-Hartman
maintainerPATCH 226/798 HID: rmi: fix OOB access with undersized RMI reports
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Wei Jie Law <[email protected]>
commit 4956993bb3befdf791d71a4952d8d13bcfd44c7b upstream.
The hid-rmi driver sizes its writeReport/readReport buffer purely from the report descriptor supplied by the device, with no minimum bound:
data->input_report_size = hid_report_len(input_report); data->output_report_size = hid_report_len(output_report); alloc_size = data->output_report_size + data->input_report_size; data->writeReport = devm_kzalloc(&hdev->dev, alloc_size, GFP_KERNEL); data->readReport = data->writeReport + data->output_report_size;
but then reads and writes fixed offsets into it. A device declaring a 1-byte output and a 1-byte input report makes hid_report_len() return 2 for each, so alloc_size is 4, while rmi_set_page() -- reached unconditionally at probe time through rmi_input_configured() -- stores writeReport[4] and rmi_hid_read_block() stores writeReport[0..5]. Since readReport lives at writeReport + output_report_size, those stores also corrupt the window the next reply is parsed out of.
The read path is worse: the copy length comes from readReport[1], which the device fills in and can be up to 255, and the copy starts at &readReport[2] with no regard for input_report_size, so it runs past the end of the allocation into adjacent slab objects. This does not even need a lying device -- rmi_f01_probe() issues a fixed 21-byte register read, so any device declaring an input report smaller than 23 bytes reads out of bounds even when it answers truthfully. Those bytes become the register values the RMI core acts on: rmi_f01_probe() prints them to the kernel log as the product id and exports them through the mode 0444 sysfs attribute of the same name, and rmi_driver_set_irq_bits() sends them back to the device as the interrupt mask, so an undersized report descriptor leaks heap contents both to unprivileged userspace and to the device itself.
The write path has no bound either: rmi_hid_write_block() copies an unbounded len to &writeReport[4], and the largest caller a device can drive at probe time is rmi_driver_set_irq_bits(), whose length is derived from the interrupt source counts the device declares in its Page Description Table.
Finally, the read loop cannot terminate on a zero-length reply: such a reply copies nothing and advances neither bytes_read nor bytes_needed, and because a reply did arrive the one second wait_event_timeout() does not fire either, so a device answering 0 forever keeps the loop running inside the probe worker with page_mutex held. khungtaskd does not notice, because every reply wakes the task.
Reject reports too small for what the driver builds -- 6 output bytes for the write reports and 3 input bytes for the read handshake -- at probe time, clamp the write and the read copy to the report sizes the device declared, and treat a zero-length reply as an error. A device refused this way is started as an ordinary HID device, like one that does not carry the RMI report ids at all.
RMI_DEVICE must not be left set in device_flags on that path, because rmi_input_configured() would then run the RMI setup and reach rmi_set_page(), which writes the writeReport buffer the refusal just skipped allocating. The bit can arrive set: rmi_probe() copies id->driver_data into device_flags before the report checks, and a bind through the new_id sysfs attribute can supply driver_data with RMI_DEVICE (BIT(0)) set. Strip the bit where driver_data is copied, so RMI_DEVICE keeps meaning exactly "this probe validated the reports"; the three jumps to start that predate this patch are covered as well.
The error path also clears RMI_READ_DATA_PENDING on its way out, because that flag is what the wait at the top of the loop tests: leaving it set would make every later wait_event_timeout() return immediately on the stale reply and kill the read path for the rest of the device's life.
Clamping does not regress working hardware: the read loop already handles a reply carrying fewer bytes than requested, and a write longer than the output report was overrunning the buffer already.
Verified on v6.12.69 and on v6.12.105 built with CONFIG_KASAN=y and booted kasan_multi_shot, whose hid-rmi.c is identical to mainline here. An emulated RMI4 device driven over /dev/uhid, and the same device again over dummy_hcd plus raw-gadget, give identical results:
BUG: KASAN: slab-out-of-bounds in rmi_hid_read_block+0x409/0x750 [hid_rmi] Read of size 21 at addr ffff88800bf33bba by task kworker/0:3/285 __asan_memcpy+0x23/0x60 rmi_hid_read_block+0x409/0x750 [hid_rmi] rmi_f01_probe+0x5dd/0x1dc0 [rmi_core] BUG: KASAN: slab-out-of-bounds in rmi_hid_write_block+0x1a9/0x350 [hid_rmi] Write of size 35 at addr ffff88810a2b24ac by task kworker/1:10/666 __asan_memcpy+0x3c/0x60 rmi_hid_write_block+0x1a9/0x350 [hid_rmi] rmi_driver_set_irq_bits+0x1f6/0x4d0 [rmi_core] rmi_driver_probe+0x636/0xbf0 [rmi_core] rmi_input_configured+0x184/0x2e0 [hid_rmi] rmi_probe+0x952/0xcf0 [hid_rmi]
and, for the zero-length reply, a probe worker left in D state in rmi_hid_read_block() after 225 replies at 200 ms intervals.
After this change the undersized descriptor is refused at probe with "rmi reports too small (out=2 in=2)", the oversized read and write are both rejected, the zero-length reply fails the read with -EIO while later reads on the same device keep working, and a device declaring reports large enough for a 21-byte register read still probes normally and reports its real product id. A device bound through new_id with RMI_DEVICE in its driver_data no longer reaches rmi_set_page() with an unallocated writeReport either.
--- drivers/hid/hid-rmi.c | 46 +++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 43 insertions(+), 3 deletions(-)
drivers/hid/hid-rmi.c +43 -3
@@ -235,7 +235,23 @@ static int rmi_hid_read_block(struct rmibreak ; } - read_input_count = data->readReport[1 ]; + read_input_count =min_t (int, data->readReport[1 ], + data->input_report_size -2 ); +if (!read_input_count) { +/* +* A zero length reply advances neither +* bytes_read nor bytes_needed, and because a +* reply did arrive the wait above does not +* time out either, so a device answering 0 +* forever would spin here indefinitely with +* page_mutex held. +*/ +hid_warn (hdev,"%s: zero-length read reply\n" , + __func__); +clear_bit (RMI_READ_DATA_PENDING , &data->flags); + ret = -EIO ; +break ; + }memcpy (buf + bytes_read, &data->readReport[2 ], read_input_count < bytes_needed ? read_input_count : bytes_needed);
@@ -272,6 +288,11 @@ static int rmi_hid_write_block(struct rm goto exit; } +if (len +4 > data->output_report_size) { + ret = -EINVAL ; + goto exit; + } + data->writeReport[0 ] =RMI_WRITE_REPORT_ID ; data->writeReport[1 ] = len; data->writeReport[2 ] = addr &0xFF ;
@@ -668,8 +689,16 @@ static int rmi_probe(struct hid_device *return ret; } -if (id->driver_data) - data->device_flags = id->driver_data; +/* +* RMI_DEVICE can only mean "this probe validated the RMI reports and +* allocated writeReport": every bail-out to start below skips that +* allocation, and device_flags left carrying RMI_DEVICE from +* driver_data would send rmi_input_configured() into rmi_set_page() +* with writeReport still NULL. A bind through the new_id sysfs +* attribute can supply driver_data with the bit set, so do not let +* driver_data grant it. +*/ + data->device_flags = id->driver_data & ~RMI_DEVICE ;/* * Check for the RMI specific report ids. If they are misisng
@@ -698,6 +727,17 @@ static int rmi_probe(struct hid_device * data->output_report_size =hid_report_len (output_report); +/* +* The write reports built by this driver occupy 6 bytes and the read +* handshake looks at the first 3 bytes of an input report, so refuse +* to drive a device whose reports cannot hold them. +*/ +if (data->output_report_size <6 || data->input_report_size <3 ) { +hid_err (hdev,"rmi reports too small (out=%u in=%u)\n" , + data->output_report_size, data->input_report_size); + goto start; + } + data->device_flags |=RMI_DEVICE ; alloc_size = data->output_report_size + data->input_report_size;
Greg Kroah-Hartman
maintainerPATCH 227/798 HID: wacom: validate report length in wacom_intuos_pro2_bt_irq
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ibrahim Hashimov <[email protected]>
commit a8e04f3f894ccb52cfcd7e60125a9f35da4a616d upstream.
wacom_intuos_pro2_bt_irq() receives the wire report length in len but never consults it before parsing. After the report-id gate it unconditionally calls wacom_intuos_pro2_bt_pen() and then, selected by features.type, a fixed chain of sub-parsers, none of which receive len:
wacom_intuos_pro2_bt_pen(wacom);
if (type == INTUOSP2_BT || type == INTUOSP2S_BT) {
wacom_intuos_pro2_bt_touch(wacom);
wacom_intuos_pro2_bt_pad(wacom);
wacom_intuos_pro2_bt_battery(wacom);
} else {
wacom_intuos_gen3_bt_pad(wacom);
wacom_intuos_gen3_bt_battery(wacom);
}Each sub-parser dereferences wacom->data at fixed offsets. The furthest byte touched on each branch is:
INTUOSP2_BT / INTUOSP2S_BT: wacom_intuos_pro2_bt_pad() reads data[285]
(the touchring byte), so the report must be at least 286 bytes;
INTUOSHT3_BT ("gen3"): wacom_intuos_gen3_bt_battery() reads data[45],
so the report must be at least 46 bytes.
features.type is selected from the VID/PID id_table entry and wacom_setup_device_quirks() force-registers the pen/pad/touch inputs for that type independent of the report descriptor, so a malicious or malfunctioning paired/spoofed Bluetooth peripheral can advertise that VID/PID and send an undersized report that still satisfies the data[0] == 0x80/0x81 gate. The driver then reads past the received report and forwards the bytes to userspace via evdev (MSC_SERIAL / ABS_MISC / ABS_WHEEL on the pen and pad input nodes), an out-of-bounds read with a concrete userspace read-back channel, and a true out-of-bounds read on transports whose backing buffer is sized to the (small) report descriptor rather than a fixed-size staging buffer.
This is the same class of bug commit 2f1763f62909 ("HID: wacom: fix out-of-bounds read in wacom_intuos_bt_irq") already hardened in the sibling wacom_intuos_bt_irq(), which guards each report id against its minimum length before parsing.
Guard wacom_intuos_pro2_bt_irq() the same way: before parsing, reject reports shorter than the furthest offset the selected branch actually dereferences, warn, and bail out. Because the whole pen/touch/pad/ battery chain runs unconditionally per branch, a single up-front check against the maximum offset (286 bytes for INTUOSP2_BT/INTUOSP2S_BT, 46 bytes for the gen3 branch) bounds every sub-parser. Returning 0 on a short report also skips those calls for the same malformed report, which is the safe, conservative behavior.
--- drivers/hid/wacom_wac.c | 13 +++++++++++++ 1 file changed, 13 insertions(+)
drivers/hid/wacom_wac.c +13 -0
@@ -1589,6 +1589,19 @@ static int wacom_intuos_pro2_bt_irq(strureturn 0 ; } +if (wacom->features.type ==INTUOSP2_BT || + wacom->features.type ==INTUOSP2S_BT ) { +if (len <286 ) { +dev_warn (wacom->pen_input->dev.parent, +"Pro2 BT report too short: %zu bytes\n" , len); +return 0 ; + } + }else if (len <46 ) { +dev_warn (wacom->pen_input->dev.parent, +"Pro2 BT report too short: %zu bytes\n" , len); +return 0 ; + } +wacom_intuos_pro2_bt_pen (wacom);if (wacom->features.type ==INTUOSP2_BT || wacom->features.type ==INTUOSP2S_BT ) {
Greg Kroah-Hartman
maintainerPATCH 228/798 dm: fix resume-vs-remove race
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikulas Patocka <[email protected]>
commit 44b43ec132f1cf3275ecc182d0c82f50c3c4c3d5 upstream.
If the user issues the resume ioctl and the remove ioctl at the same time, it may be possible that the device is resumed after it is suspended in __dm_destroy. The result is that the table is destroyed without calling the postsuspend method.
Dm targets expect that they may be removed only after the postsuspend method method was called. If we break this expectation, it can cause misbehavior in various targets. For example - in the dm-integrity target, the reboot notifier is not unregistered, leading to use-after-free.
Fix this bug by refusing to resume if the device is being destroyed.
--- drivers/md/dm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/md/dm.c +1 -1
@@ -2629,7 +2629,7 @@ retry: r = -EINVAL ;mutex_lock_nested (&md->suspend_lock,SINGLE_DEPTH_NESTING ); -if (!dm_suspended_md (md)) +if (!dm_suspended_md (md) ||test_bit (DMF_FREEING , &md->flags)) goto out;if (dm_suspended_internally_md (md)) {
Greg Kroah-Hartman
maintainerPATCH 229/798 dmaengine: dw-edma: Complete descriptors before pausing
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Koichiro Den <[email protected]>
commit c154060016a9db2ac889bfdb0a3c1322f9be8ded upstream.
If PAUSE is requested while the final burst of a descriptor is in flight, the DONE interrupt takes the PAUSE path without checking whether the descriptor has been depleted. The depleted descriptor remains on the issued list and the channel enters EDMA_ST_PAUSE.
On resume, dw_edma_start_transfer() can select that depleted descriptor again even though no burst remains, leaving the channel in an invalid busy state.
Check for descriptor completion before acknowledging PAUSE. If there is no work to start on resume, leave the channel idle. Also ignore DONE interrupts while the channel is paused so a stale or repeated interrupt cannot change its state or start queued work.
--- drivers/dma/dw-edma/dw-edma-core.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-)
drivers/dma/dw-edma/dw-edma-core.c +14 -6
@@ -241,7 +241,8 @@ static int dw_edma_device_resume(struct err = -EPERM ; }else { chan->status =EDMA_ST_BUSY ; -dw_edma_start_transfer (chan); +if (!dw_edma_start_transfer (chan)) + chan->status =EDMA_ST_IDLE ; }return err;
@@ -521,10 +522,16 @@ static void dw_edma_done_interrupt(strucdw_edma_v0_core_clear_done_int (chan);spin_lock_irqsave (&chan->vc.lock, flags); +if (chan->status ==EDMA_ST_PAUSE ) { +spin_unlock_irqrestore (&chan->vc.lock, flags); +return ; + } + vd =vchan_next_desc (&chan->vc);if (vd) {switch (chan->request) {case EDMA_REQ_NONE : +case EDMA_REQ_PAUSE : desc =vd2dw_edma_desc (vd);if (!desc->chunks_alloc) { dw_hdma_set_callback_result(vd,
@@ -533,6 +540,12 @@ static void dw_edma_done_interrupt(strucvchan_cookie_complete (vd); } +if (chan->request ==EDMA_REQ_PAUSE ) { + chan->request =EDMA_REQ_NONE ; + chan->status =EDMA_ST_PAUSE ; +break ; + } +/* Continue transferring if there are remaining chunks or issued requests. */ chan->status =dw_edma_start_transfer (chan) ?EDMA_ST_BUSY :EDMA_ST_IDLE ;
@@ -545,11 +558,6 @@ static void dw_edma_done_interrupt(struc chan->status =EDMA_ST_IDLE ;break ; -case EDMA_REQ_PAUSE : - chan->request =EDMA_REQ_NONE ; - chan->status =EDMA_ST_PAUSE ; -break ; -default :break ; }
Greg Kroah-Hartman
maintainerPATCH 230/798 ata: ahci: work around lost interrupts on Marvell 88SE61xx
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hajo Noerenberg <[email protected]>
commit dc3565a4ae538e584e5e63b3b3cd1eaf502593c1 upstream.
ahci_single_level_irq_intr() services the ports first and clears the global HOST_IRQ_STAT afterwards, as recommended by AHCI 1.1 section 10.6.2. The Marvell 88SE6111/6121/6145 family stops reporting interrupts for a port when HOST_IRQ_STAT is cleared while PxIS still holds bits:
PxIS keeps its content, HOST_IRQ_STAT reads back as 0, the port is never looked at again, and the command in flight only ends in a timeout.
Measured on a Seagate Blackarmor NAS440 (Marvell 88F6281 Kirkwood, 88SE6121 rev B2 behind PCIe) by polling the AHCI registers from userspace while an IDENTIFY was outstanding:
t=303.046 irqs 127 PxIS 0x00000000 PxCI 0x00000001
IDENTIFY issued
t=303.057 irqs 128 PxIS 0x00000020 PxCI 0x00000000
CI cleared, DPS set, one interrupt taken ... PxIS stays 0x00000020, HOST_IRQ_STAT stays 0 ...
t~308.05 qc timeout after 5000 msecs
The command had completed - PxCI was clear and PxIS had DPS set - so ahci_qc_complete() would have completed it. It never got the chance because the handler read HOST_IRQ_STAT as 0 and returned IRQ_NONE.
Marvell's own driver for these chips clears the two registers in the opposite order and says so ("clear global before channel"), and ahci_xgene handles its broken edge latch the same way. Since the reordering costs at most one spurious interrupt per valid one on conforming controllers, do it in a private interrupt handler selected for board_ahci_mv instead of changing libahci for everyone.
With this applied, SATA-2 and SATA-3 disks work at 3.0 Gbps on the 88SE6121 without the drive-side 1.5 Gbps jumper that was needed before. Time from link up to a successful IDENTIFY:
WDC WD5000AADS-00S9B0 port 0 7 ms (never identified before) WDC WD3202ABYS-01B7A0 port 1 28 ms WDC WD30EFRX-68EUZN0 port 1 200 ms (3 TB, HPA detection ok)
Only the 88SE6121 was tested; board_ahci_mv also covers the 88SE6145, which Marvell's driver treats identically.
--- drivers/ata/ahci.c | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+)
drivers/ata/ahci.c +49 -0
@@ -1560,6 +1560,51 @@ static irqreturn_t ahci_thunderx_irq_han }#endif +/* +* The Marvell 88SE6111/6121/6145 ("Thor") family stops reporting interrupts +* for a port when HOST_IRQ_STAT is cleared while PxIS still holds bits: PxIS +* keeps its content, HOST_IRQ_STAT reads back as 0, the port is never looked +* at again and the command in flight only ends in a timeout. On a 88SE6121 +* this makes every SATA-2 or SATA-3 disk fail to IDENTIFY, while SATA-1 disks +* happen to win the race often enough to work. +* +* Clearing the host status before servicing the ports avoids it. Marvell's +* own driver for these chips does the same and says so ("clear global before +* channel"), and ahci_xgene handles its broken edge latch the same way. The +* price is at most one spurious interrupt per valid one, which is why this is +* not the generic behaviour - see AHCI 1.1 section 10.6.2. +* +* Link: https://bugzilla.kernel.org/show_bug.cgi?id=216094 +*/ +static irqreturn_t ahci_mv_irq_handler (int irq,void *dev_instance) +{ +struct ata_host *host = dev_instance; +struct ahci_host_priv *hpriv = host->private_data; +void __iomem *mmio = hpriv->mmio; +unsigned int rc; +u32 irq_stat, irq_masked; + + irq_stat =readl (mmio +HOST_IRQ_STAT ); +if (!irq_stat) +return IRQ_NONE ; + + irq_masked = irq_stat & hpriv->port_map; + +spin_lock (&host->lock); + +/* +* Use the unmasked value to clear the interrupt, as a spurious pending +* event on a dummy port might cause a screaming IRQ. +*/ +writel (irq_stat, mmio +HOST_IRQ_STAT ); + + rc =ahci_handle_port_intr (host, irq_masked); + +spin_unlock (&host->lock); + +return IRQ_RETVAL (rc); +} +static void ahci_remap_check (struct pci_dev *pdev,int bar,struct ahci_host_priv *hpriv) {
@@ -1808,6 +1853,10 @@ static int ahci_init_one(struct pci_devreturn -ENOMEM ; hpriv->flags |= (unsigned long )pi.private_data; +/* the Marvell "Thor" family needs HOST_IRQ_STAT cleared first */ +if (board_id == board_ahci_mv) + hpriv->irq_handler = ahci_mv_irq_handler; +/* MCP65 revision A1 and A2 can't do MSI */ if (board_id == board_ahci_mcp65 && (pdev->revision ==0xa1 || pdev->revision ==0xa2 ))
Greg Kroah-Hartman
maintainerPATCH 231/798 perf/x86/intel: Fix kernel address leakages in LBR stack
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dapeng Mi <[email protected]>
commit e2b0575900ff72aa82748af96e7bd564ade5157a upstream.
Before Arch LBR gained CPL filtering support, a user-only branch stack could still contain kernel addresses. As a result, kernel branch records may be exposed to user space even when PERF_SAMPLE_BRANCH_USER is requested.
For example, on Intel Tiger Lake, the following command can still report SYSRET/ERET entries with kernel-space from addresses:
$ ./perf record -e cycles:p -o - --branch-filter any,save_type,u -- \
./perf bench syscall basic --loop 1000 | \
./perf script -i - --fields brstack|tr ' ' '\n'| \
grep -E '0x[89a-f][0-9a-f]{15}' Total time: 0.000 [sec]
0.219000 usecs/op
4,566,210 ops/sec[ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.551 MB - ] 0xffffffff93c001c8/0x7f12a2b1d647/P/-/-/16959/SYSRET/- 0xffffffff93c001c8/0x7f12a2b1d5c2/P/-/-/17535/SYSRET/- 0xffffffff93c01928/0x7f12a2861000/P/-/-/6719/ERET/- 0xffffffff93c01928/0x7f12a297a000/P/-/-/8575/ERET/-
The problem is that intel_pmu_lbr_filter() does not fully validate the privilege level of sampled entries. It filters some mismatches based on the branch type and the to address, but it does not reject entries whose from address violates the requested branch privilege filter.
Fix this by extending software filtering to validate both from and to addresses against br_sel. Any LBR entry contains kernel address does not match the requested user filter is dropped. This prevents kernel addresses from appearing in user-only branch stacks.
--- arch/x86/events/intel/lbr.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-)
arch/x86/events/intel/lbr.c +9 -3
@@ -1414,7 +1414,7 @@ intel_pmu_lbr_filter(struct cpu_hw_event {u64 from, to;int br_sel = cpuc->br_sel; -int i, j, type, to_plm; +int i, j, type, from_plm, to_plm;bool compress = false;/* if sampling all branches, then nothing to filter */
@@ -1446,8 +1446,14 @@ intel_pmu_lbr_filter(struct cpu_hw_event type |=X86_BR_NO_TX ; } -/* if type does not correspond, then discard */ -if (type ==X86_BR_NONE || (br_sel & type) != type) { + from_plm =kernel_ip (from) ?X86_BR_KERNEL :X86_BR_USER ; +/* +* If type does not correspond, then discard. +* Specifically reject entries whose from address is in +* kernel space when only X86_BR_USER is requested. +*/ +if (type ==X86_BR_NONE || (br_sel & type) != type || + (!(br_sel &X86_BR_KERNEL ) && (from_plm &X86_BR_KERNEL ))) { cpuc->lbr_entries[i].from =0 ; compress = true; }
Greg Kroah-Hartman
maintainerPATCH 232/798 i2c: mux: Fix channel node leak on adapter add failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ahmad Byagowi <[email protected]>
commit 385c7af4e3b95d0769fd211831674e83b16a2ebf upstream.
i2c_mux_add_adapter() takes a reference to the Device Tree channel node before registering the new adapter. If adapter registration fails, the error path frees the private data without dropping that reference.
Release the channel node before freeing the private data.
--- drivers/i2c/i2c-mux.c | 1 + 1 file changed, 1 insertion(+)
drivers/i2c/i2c-mux.c +1 -0
@@ -432,6 +432,7 @@ int i2c_mux_add_adapter(struct i2c_mux_creturn 0 ; err_free_priv: +of_node_put (priv->adap.dev.of_node);kfree (priv);return ret; }
Greg Kroah-Hartman
maintainerPATCH 233/798 ALSA: pcm: Fix race between non-atomic ops and trigger-start
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Takashi Iwai <[email protected]>
commit acac7b5e07349a9d10d78873afb4b93cd1dc721f upstream.
We protect the races of the concurrent state transitions between atomic PCM ops, but the checks between the non-atomic ops (hw_params, hw_free and prepare) and the atomic ops aren't perfect; there is a check of the conflicting PCM state at the beginning of hw_params & co, but the atomic PCM ops can be still issued during the non-atomic PCM operations. An example such scenario is that a thread A re-issues the PREPARE or HW_PARAMS for the already prepared stream, while another thread B triggers the PCM start in the middle of the prepare operation. Although this usually doesn't lead to much serious issues, it can give some inconsistency as reported by syzkaller (such as ODEBUG warning).
There are various atomic PCM ops, and basically the only problem is the PCM start as it operates from the PREPARED state. Other trigger commands (stop, etc) are for the running or the other special state, hence they are filtered as pre-condition.
This patch is for preventing the PCM trigger-start during the non- atomic operations in order to address the problems above. Fortunately, the hw_params, hw_free and prepare operations call snd_pcm_buffer_access_lock(), and this can be used for checking the concurrent operations at the PCM trigger -- which sets the runtime->buffer_accessing to a negative (if possible), so the PCM trigger just needs to check the runtime->buffer_accessing value; if it's negative, it means the concurrent non-atomic PCM ops is running.
--- sound/core/pcm_native.c | 2 ++ 1 file changed, 2 insertions(+)
sound/core/pcm_native.c +2 -0
@@ -1411,6 +1411,8 @@ static int snd_pcm_pre_start(struct snd_struct snd_pcm_runtime *runtime = substream->runtime;if (runtime->status->state !=SNDRV_PCM_STATE_PREPARED )return -EBADFD ; +if (atomic_read (&runtime->buffer_accessing) <0 ) +return -EBADFD ;/* during hw_params, hw_free or prepare */ if (substream->stream ==SNDRV_PCM_STREAM_PLAYBACK && !snd_pcm_playback_data (substream))return -EPIPE ;
Greg Kroah-Hartman
maintainerPATCH 234/798 nvme-tcp: check the data direction of a C2HData PDU
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Yehyeong Lee <[email protected]>
commit f83af377c148f6ad94b41c0e8313f12adf45e1c1 upstream.
nvme_tcp_handle_c2h_data() finds the request by command id and checks that it has a payload, but it does not check that the command asked for data to be read. A controller that answers a write command with C2HData therefore reaches nvme_tcp_recv_data(), where _copy_to_iter() hits WARN_ON_ONCE(i->data_source) and returns 0. The receive path turns that into -EFAULT and resets the controller.
No data is copied, so this is not memory corruption. What a controller gets is a kernel warning it can raise at will, which is fatal on a host booted with panic_on_warn.
The send path already knows the direction - it consults rq_data_dir() when it builds a command - and nvme_tcp_handle_r2t() checks the length and the offset of the request it names. The C2HData path does not check the direction at all.
Reject a C2HData PDU whose command is not a read. Rejecting it fails the command and resets the controller, as the neighbouring check in this function does; what goes away is the warning.
[ 6.885580] ------------[ cut here ]------------ [ 6.886457] WARNING: lib/iov_iter.c:193 at _copy_to_iter+0x289/0x1330, CPU#0: kworker/0:1H/71 [ 6.888137] CPU: 0 UID: 0 PID: 71 Comm: kworker/0:1H Not tainted 7.2.0-rc5-NVMETCP-gf5098b6bae76 #1 PREEMPT(lazy) [ 6.891165] Workqueue: nvme_tcp_wq nvme_tcp_io_work [ 6.891875] RIP: 0010:_copy_to_iter+0x289/0x1330 [ 6.903739] Call Trace: [ 6.904085] <TASK> [ 6.909254] __skb_datagram_iter+0x433/0x820 [ 6.911026] skb_copy_datagram_iter+0x37/0x120 [ 6.911622] nvme_tcp_recv_skb+0xa07/0x4320 [ 6.913378] __tcp_read_sock+0x1ab/0x810 [ 6.915788] nvme_tcp_try_recv+0x152/0x1e0 [ 6.918222] nvme_tcp_io_work+0x1e4/0x6c0 [ 6.926906] </TASK> [ 6.927226] ---[ end trace 0000000000000000 ]--- [ 6.927878] nvme nvme0: queue 1 failed to copy request 0x71 data [ 6.928709] nvme nvme0: receive failed: -14
--- drivers/nvme/host/tcp.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/nvme/host/tcp.c +7 -0
@@ -556,6 +556,13 @@ static int nvme_tcp_handle_c2h_data(strureturn -ENOENT ; } +if (rq_data_dir (rq) !=READ ) { +dev_err (queue->ctrl->ctrl.device, +"queue %d tag %#x unexpected data for a write\n" , +nvme_tcp_queue_id (queue), rq->tag); +return -EIO ; + } + req =blk_mq_rq_to_pdu (rq);if (!blk_rq_payload_bytes (rq) || !req->curr_bio || !req->data_len) { dev_err(queue->ctrl->ctrl.device,
Greg Kroah-Hartman
maintainerPATCH 235/798 nvmet-tcp: fix out-of-bounds write when receiving an over-long PDU
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivam Kumar <[email protected]>
commit 14cc5a7e77731497d5bea70f3bb05df7eda982e4 upstream.
nvmet_tcp_try_recv_pdu() reads a PDU header into the fixed 128-byte queue->pdu union, then computes the remaining payload length as
queue->left = hdr->hlen - queue->offset + hdgst;
and reads that many more bytes into &queue->pdu + queue->offset, without ever bounding the result against sizeof(queue->pdu).
A struct nvme_tcp_icreq_pdu is itself 128 bytes, exactly the size of the union. Once a header digest has been negotiated (hdgst = 4), a second ICReq passes the hlen == nvmet_tcp_pdu_size() check but yields queue->left = 128 - 8 + 4 = 124, so bytes 8..132 are written into the 128-byte buffer -- 4 bytes past its end, over queue->hdr_digest and queue->data_digest. Those bytes are attacker-controlled (an ICReq carries no digest), and the duplicate ICReq is only rejected later, after the overflow. A remote unauthenticated host can thus corrupt kernel memory adjacent to the receive buffer.
Reject any PDU whose declared length would read past the end of queue->pdu before the second recv.
--- drivers/nvme/target/tcp.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/nvme/target/tcp.c +2 -0
@@ -1161,6 +1161,8 @@ recv: } queue->left = hdr->hlen - queue->offset + hdgst; +if (queue->left >sizeof (queue->pdu) - queue->offset) +return -EPROTO ; goto recv; }
Greg Kroah-Hartman
maintainerPATCH 236/798 nvmet-tcp: reject unsolicited H2CData PDUs
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Shivam Kumar <[email protected]>
commit db62b35cbca052860c519cbcabe7650708528738 upstream.
nvmet_tcp_handle_h2c_data_pdu() accepts an H2CData PDU after only checking that its TTAG is a valid in-range command index and that the command's data buffers are mapped. It never checks that the target has actually solicited that data by sending an R2T for the command.
A remote host can abuse this. It submits a write command that takes the R2T path and, before the target transmits the R2T, sends an H2CData PDU for that command's tag. The data completes the command early, and when the command then fails synchronously (e.g. a length mismatch caught by nvmet_check_transfer_len()), it is completed a second time. Each completion calls nvmet_tcp_queue_response(), so the same command is added to queue->resp_list twice while it is still linked; the second llist_add() makes the node point to itself (lentry->next == lentry).
nvmet_tcp_process_resp_list() then walks that self-referential node and adds the command to resp_send_list twice. With CONFIG_DEBUG_LIST this trips the "list_add double add" check (kernel BUG); without it the loop never terminates and the nvmet_tcp workqueue wedges (soft-lockup). It is remotely triggerable and needs no authentication on an allow_any_host subsystem.
Track whether an R2T has been transmitted for a command and reject an H2CData PDU that arrives before it. The flag is cleared on command reuse (nvmet_tcp_get_cmd() zeroes cmd->flags) and stays set across the multiple H2CData PDUs of a single solicited transfer.
--- drivers/nvme/target/tcp.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/nvme/target/tcp.c +8 -0
@@ -51,6 +51,7 @@ enum nvmet_tcp_recv_state {enum {NVMET_TCP_F_INIT_FAILED = (1 <<0 ), +NVMET_TCP_F_R2T_SENT = (1 <<1 ), };struct nvmet_tcp_cmd {
@@ -714,6 +715,7 @@ static int nvmet_try_send_r2t(struct nvmreturn -EAGAIN ; cmd->queue->snd_cmd =NULL ; + cmd->flags |=NVMET_TCP_F_R2T_SENT ;return 1 ; }
@@ -978,6 +980,12 @@ static int nvmet_tcp_handle_h2c_data_pdu cmd = &queue->connect; } +if (unlikely (!(cmd->flags &NVMET_TCP_F_R2T_SENT ))) { +pr_err ("queue %d: unsolicited H2CData (ttag %u)\n" , + queue->idx, data->ttag); + goto err_proto; + } +if (le32_to_cpu (data->data_offset) != cmd->rbytes_done) { pr_err("ttag %u unexpected data offset %u (expected %u)\n", data->ttag, le32_to_cpu(data->data_offset),
Greg Kroah-Hartman
maintainerPATCH 237/798 Revert "irqchip/mbigen: Fix mbigen node address layout"
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: caina <[email protected]>
commit e67091609cf85962f64391c1b0f93d4cbfcd4e22 upstream.
This reverts commit 6be6cba9c4371d27f78d900ccfe34bb880d9ee20.
Commit 6be6cba9c437 ("irqchip/mbigen: Fix mbigen node address layout") appears to cause a regression on Hi1616.
On-board hns NIC has two ports, enahisic2i0 and enahisic2i1, both behind mbigen-v2. Port 0 works; port 1 cannot pass any traffic.
Their interrupt pins fall on different mbigen nodes:
enahisic2i0: pins 1152-1198 -> all in node 9
enahisic2i1: pins 1200-1246 -> node 9 (1200-1215) + node 10 (1216-1246)
(nid = (hwirq - 64) / 128 + 1; pin 1215 = node 9, pin 1216 = node 10)
/proc/interrupts shows the break happens exactly at the node boundary:
enahisic2i1-rx0 pin 1200 count 102 <- node 9 enahisic2i1-rx5 pin 1215 count 1 <- node 9, last pin enahisic2i1-tx5 pin 1216 count 0 <- node 10, first pin enahisic2i1-rx6 pin 1218 count 0 <- node 10
...all node 10 pins stay at zero.
Port 0 (entirely node 9) is unaffected. Reverting the commit restores normal operation.
The commit assumes CLEAR occupies a full 4 KB page at [0xa000, 0xb000) and collides with node 10, so node 10+ gets shifted by 0x1000.
But get_mbigen_clear_reg() uses flat, chip-wide addressing -- it never multiplies by the node ID:
*addr = (hwirq / 32) * 4 + REG_MBIGEN_CLEAR_OFFSET; /* 0xa000 */
Over the valid hwirq range [64, 1407], CLEAR only spans 0xa008-0xa0af (168 bytes). Node 10's registers are:
TYPE: 0xa000-0xa00f (16 B) overlaps CLEAR by 8 B (0xa008-0xa00f)
VEC: 0xa200-0xa3ff (512 B) no overlap with CLEARShifting the whole page moves VEC from 0xa200 to 0xb200. The hardware reads the event ID from the fixed silicon address 0xa200 on interrupt firing, but software wrote it to 0xb200 -- so the hardware gets an uninitialised value and the interrupt is lost.
The only real overlap is 8 bytes of TYPE. It can only trigger when a single mbigen instance has devices on both node 1 (CLEAR 0xa008) and node 10 (TYPE 0xa008). On Hi1616 those nodes are on separate mbigen instances, so it never triggers.
--- drivers/irqchip/irq-mbigen.c | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-)
drivers/irqchip/irq-mbigen.c +4 -16
@@ -64,20 +64,6 @@ struct mbigen_device {void __iomem *base; }; -static inline unsigned int get_mbigen_node_offset (unsigned int nid) -{ -unsigned int offset = nid *MBIGEN_NODE_OFFSET ; - -/* -* To avoid touched clear register in unexpected way, we need to directly -* skip clear register when access to more than 10 mbigen nodes. -*/ -if (nid >= (REG_MBIGEN_CLEAR_OFFSET /MBIGEN_NODE_OFFSET )) - offset +=MBIGEN_NODE_OFFSET ; - -return offset; -} -static inline unsigned int get_mbigen_vec_reg (irq_hw_number_t hwirq) {unsigned int nid, pin;
@@ -86,7 +72,8 @@ static inline unsigned int get_mbigen_ve nid = hwirq /IRQS_PER_MBIGEN_NODE +1 ; pin = hwirq %IRQS_PER_MBIGEN_NODE ; -return pin *4 +get_mbigen_node_offset (nid) +REG_MBIGEN_VEC_OFFSET ; +return pin *4 + nid *MBIGEN_NODE_OFFSET + +REG_MBIGEN_VEC_OFFSET ; } static inline void get_mbigen_type_reg(irq_hw_number_t hwirq,
@@ -101,7 +88,8 @@ static inline void get_mbigen_type_reg(i *mask =1 << (irq_ofst %32 ); ofst = irq_ofst /32 *4 ; - *addr = ofst +get_mbigen_node_offset (nid) +REG_MBIGEN_TYPE_OFFSET ; + *addr = ofst + nid *MBIGEN_NODE_OFFSET + +REG_MBIGEN_TYPE_OFFSET ; } static inline void get_mbigen_clear_reg(irq_hw_number_t hwirq,
Greg Kroah-Hartman
maintainerPATCH 238/798 nvdimm/btt: reject an arena whose nfree is below the lane count
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 6a1f2e5ed9267ca19187038ac635393c165213ac upstream.
The BTT info block's nfree field, the number of reserve free blocks, is read from the medium without validation. btt_freelist_init() and btt_rtt_init() size the per-lane freelist[] and rtt[] arrays by nfree, but the I/O path indexes them by the lane from nd_region_acquire_lane(), which is bounded by nd_region->num_lanes (ND_MAX_LANES), not by nfree. A crafted or foreign arena whose nfree is below the lane count makes freelist[lane]/rtt[lane] run past the allocation: an out-of-bounds write.
btt.rst documents the nlanes = min(nfree, num_cpus) invariant, which the code does not currently honor: num_lanes is ND_MAX_LANES regardless of nfree. Reject an arena whose nfree is below num_lanes at discovery, before the per-lane arrays are allocated, enforcing that invariant.
--- drivers/nvdimm/btt.c | 8 ++++++++ 1 file changed, 8 insertions(+)
drivers/nvdimm/btt.c +8 -0
@@ -886,6 +886,14 @@ static int discover_arenas(struct btt *b arena->external_lba_start = cur_nlba;parse_arena_meta (arena, super, cur_off); +if (arena->nfree < btt->nd_region->num_lanes) { +dev_err (to_dev (arena), +"nfree %u smaller than lane count %d\n" , + arena->nfree, btt->nd_region->num_lanes); + ret = -ENODEV ; + goto out; + } + ret =log_set_indices (arena);if (ret) { dev_err(to_dev(arena),
Greg Kroah-Hartman
maintainerPATCH 239/798 parisc: eisa: Fix infinite loop when parsing invalid IRQ value
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pei Xiao <[email protected]>
commit 8b585431a16cfb9d8f2955a9fa0787ce3dceb3c2 upstream.
When an invalid value is passed via the "eisa_irq_edge=" kernel command line parameter (e.g. "eisa_irq_edge=16,5"), eisa_irq_setup() prints an error message and continues without advancing the current position. As a result the same invalid value is parsed again and again, causing an infinite loop while the kernel boots.
Advance to the next comma-separated entry, or stop parsing when there is no next entry, before continuing so that the remaining entries are processed normally.
--- drivers/parisc/eisa.c | 5 +++++ 1 file changed, 5 insertions(+)
drivers/parisc/eisa.c +5 -0
@@ -441,6 +441,11 @@ static int __init eisa_irq_setup(char *s val = (int )simple_strtoul (cur, &pe,0 );if (val >15 || val <0 ) {printk (KERN_ERR "eisa: EISA irq value are 0-15\n" ); + cur =strchr (cur,',' ); +if (cur) + cur++; +else +break ;continue ; }if (val ==2 ) {
Greg Kroah-Hartman
maintainerPATCH 240/798 parisc: Fix alignment of asm statements in head.S
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Helge Deller <[email protected]>
commit 04cf68c9a76e3c6b67ad056a66a14923abf85925 upstream.
All assembler statements need to be 4-byte aligned. Prevent a possible misalignment if someone changes the preceeding string and it's length is then suddenly not a multiple of 4 any longer.
--- arch/parisc/kernel/head.S | 1 + 1 file changed, 1 insertion(+)
arch/parisc/kernel/head.S +1 -0
@@ -104,6 +104,7 @@ $iodc_panic: or %r10,%r10,%r10 /* qemu idle sleep */ msg1: .ascii "Can't boot kernel which was built for PA8x00 CPUs on this machine.\r\n" msg1_end: + .align 4 $cpu_ok: #endif
Greg Kroah-Hartman
maintainerPATCH 241/798 mtd: afs: validate v2 image info bounds
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit e9290031f736e99ad17c25c00311c92c266843b7 upstream.
The AFS v2 parser uses footer[8] to locate the image information block inside the current erase block, then uses the image information region_count to walk entries from a fixed local array. The footer offset and region count come from flash contents and are not checked against the erase block or the local image-info array before use.
Reject v2 entries whose image information offset would underflow the erase block calculation, and reject region counts that cannot fit in the local image-info array before walking region entries.
--- drivers/mtd/parsers/afs.c | 7 +++++++ 1 file changed, 7 insertions(+)
drivers/mtd/parsers/afs.c +7 -0
@@ -235,6 +235,9 @@ static int afs_parse_v2_partition(structpr_debug ("Parsing v2 partition @%08x-%08x\n" , off, off + mtd->erasesize); +if (mtd->erasesize <sizeof (footer)) +return -EINVAL ; +/* First read the footer */ ptr = off + mtd->erasesize -sizeof (footer); ret =mtd_read (mtd, ptr,sizeof (footer), &sz, (u_char *)footer);
@@ -245,6 +248,8 @@ static int afs_parse_v2_partition(struct } name = (char *) &footer[0 ]; version = footer[9 ]; +if (footer[8 ] > mtd->erasesize -sizeof (footer)) +return -EINVAL ; ptr = off + mtd->erasesize -sizeof (footer) - footer[8 ]; pr_debug("found image \"%s\", version %08x, info @%08x\n",
@@ -278,6 +283,8 @@ static int afs_parse_v2_partition(struct entrypoint = imginfo[pad]; attributes = imginfo[pad+1 ]; region_count = imginfo[pad+2 ]; +if (region_count > (ARRAY_SIZE (imginfo) - pad -3 ) /4 ) +return -EINVAL ; block_start = imginfo[20 ]; block_end = imginfo[21 ];
Greg Kroah-Hartman
maintainerPATCH 242/798 mtd: mtdoops: free page bitmap when the backing MTD is removed
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit 956e7da12c114f13c63d126ab1d79c3b6a819060 upstream.
mtdoops_notify_add() allocates oops_page_used when the configured MTD device is registered. mtdoops_notify_remove() detaches from that device but leaves the bitmap allocated. If the same MTD device is later registered again, the add path allocates a new bitmap and overwrites the old pointer, leaking one vmalloc allocation per remove/add cycle.
This is only visible when the backing MTD device can disappear and be registered again while mtdoops remains loaded, so the usual static MTD case does not expose it.
Free the bitmap after unregistering the dumper and flushing the pending workers, then clear the pointer and page count before a later attach can allocate fresh state. Clearing the pointer also keeps the module exit path from freeing the same bitmap a second time after a remove event.
--- drivers/mtd/mtdoops.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/mtd/mtdoops.c +3 -0
@@ -355,6 +355,9 @@ static void mtdoops_notify_remove(struct cxt->mtd =NULL ;flush_work (&cxt->work_erase);flush_work (&cxt->work_write); +vfree (cxt->oops_page_used); + cxt->oops_page_used =NULL ; + cxt->oops_pages =0 ; }
Greg Kroah-Hartman
maintainerPATCH 243/798 mtd: rawnand: validate ONFI extended parameter page sections
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Pengpeng Hou <[email protected]>
commit e5e415262330bd70f983e091d8919d9dcd99e475 upstream.
nand_flash_detect_ext_param_page() allocates the length declared by the ONFI parameter page, then treats the data as a fixed header followed by variable-length sections. It reads that header and advances over sections without first proving that the fixed page and each current section fit in the allocation.
Reject pages shorter than the fixed header, track the remaining variable area while walking sections, and require the ECC section to contain every field read from struct onfi_ext_ecc_info. Use device-scoped diagnostics that identify the malformed ONFI section.
--- drivers/mtd/nand/raw/nand_onfi.c | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-)
drivers/mtd/nand/raw/nand_onfi.c +25 -2
@@ -35,16 +35,21 @@ static int nand_flash_detect_ext_param_p struct nand_onfi_params *p) {struct nand_device *base = &chip->base; +struct mtd_info *mtd =nand_to_mtd (chip);struct nand_ecc_props requirements;struct onfi_ext_param_page *ep;struct onfi_ext_section *s;struct onfi_ext_ecc_info *ecc; +size_t remaining, section_len;uint8_t *cursor;int ret;int len;int i; len =le16_to_cpu (p->ext_param_page_length) *16 ; +if (len <sizeof (*ep)) +return -EINVAL ; + ep =kmalloc (len,GFP_KERNEL );if (!ep)return -ENOMEM ;
@@ -77,11 +82,29 @@ static int nand_flash_detect_ext_param_p/* find the ECC section. */ cursor = (uint8_t *)(ep +1 ); + remaining = len -sizeof (*ep);for (i =0 ; i <ONFI_EXT_SECTION_MAX ; i++) { s = ep->sections + i; -if (s->type ==ONFI_SECTION_TYPE_2 ) + section_len = s->length *16 ; +if (section_len > remaining) { +dev_dbg (&mtd->dev, +"ONFI extended parameter section %d exceeds page\n" , + i); + goto ext_out; + } + +if (s->type ==ONFI_SECTION_TYPE_2 ) { +if (section_len <sizeof (*ecc)) { +dev_dbg (&mtd->dev, +"ONFI extended parameter ECC section %d is too short\n" , + i); + goto ext_out; + }break ; - cursor += s->length *16 ; + } + + cursor += section_len; + remaining -= section_len; }if (i ==ONFI_EXT_SECTION_MAX ) {pr_debug ("We can not find the ECC section.\n" );
Greg Kroah-Hartman
maintainerPATCH 244/798 batman-adv: fix stale receive device on merged fragments
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhiling Zou <[email protected]>
commit ad46c907d7d9975a285c1e89a4adde652eaa93f5 upstream.
Fragment reassembly reuses the skb from the highest-numbered buffered fragment as the merged packet. When that fragment was received on a hard interface which is deleted before the chain completes, the merged skb can re-enter the receive path with a stale skb->dev and skb_iif.
batadv_batman_skb_recv() passes such merged packets through the normal receive handlers again. DAT and bridge loop avoidance both derive the ARP header length from skb->dev, so they can dereference the freed net_device before the packet reaches the local mesh interface.
Refresh the receive device metadata from the current receive device before running the packet handlers. This keeps internally reinjected merged fragments consistent with the normal receive path after hard interface teardown.
--- net/batman-adv/main.c | 4 ++++ 1 file changed, 4 insertions(+)
net/batman-adv/main.c +4 -0
@@ -511,6 +511,10 @@ int batadv_batman_skb_recv(struct sk_bufif (!skb) goto err_put; +/* Merged fragments re-enter here with reused skb metadata. */ + skb->dev = dev; + skb->skb_iif = dev->ifindex; +/* packet should hold at least type and version */ if (unlikely (!pskb_may_pull (skb,2 ))) goto err_free;
Greg Kroah-Hartman
maintainerPATCH 245/798 batman-adv: dat: avoid unaligned fault in IP extraction
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 0121afa52cdb88cfb4d5d7bd126a23a9100121d8 upstream.
Independent of the alignment of the ARP packet in the SKB, either the batadv_arp_ip_src or the batadv_arp_ip_dst will have an unaligned access (on HW without native unaligned read support).
Use get_unaligned() to handle this properly on all architectures.
--- net/batman-adv/distributed-arp-table.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-)
net/batman-adv/distributed-arp-table.c +6 -2
@@ -251,7 +251,10 @@ static u8 *batadv_arp_hw_src(struct sk_b*/ static __be32 batadv_arp_ip_src (struct sk_buff *skb,int hdr_size) { -return *(__force __be32 *)(batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN ); +u8 *src =batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN ; +__be32 *ip = (__force __be32 *)src; + +return get_unaligned (ip); }/**
@@ -276,8 +279,9 @@ static u8 *batadv_arp_hw_dst(struct sk_bstatic __be32 batadv_arp_ip_dst (struct sk_buff *skb,int hdr_size) {u8 *dst =batadv_arp_hw_src (skb, hdr_size) +ETH_ALEN *2 +4 ; +__be32 *ip = (__force __be32 *)dst; -return *(__force __be32 *)dst; +return get_unaligned (ip); }/**
Greg Kroah-Hartman
maintainerPATCH 246/798 batman-adv: bla: fix freeing of claims on meshif deletion
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 8d128c932bced74e3b1625ba3d7c78ef122a88a7 upstream.
When the mesh interface is getting deleted, then batadv_bla_del_backbone_claims() (via batadv_bla_purge_backbone_gw()) could make sure that all claims gets removed. But this function is only executed when bat_priv->bla.claim_hash is not NULL. And since batadv_bla_free() is always setting it to NULL before it is (indirectly) called, it was never actually executed.
But the batadv_bla_purge_claims() -> batadv_handle_unclaim() is at the moment too fragile because the BLA code is not handling the rehashing in batadv_bla_update_orig_address(). The stored backbone address doesn't have to be the one actually used for the hash bucket selection during the initial adding of the backbone. The batadv_handle_unclaim() can therefore fail to find the respective backbone for the unclaim and then stop the deletion.
But the actual backbone_gw object is not needed for the unclaim because all relevant information is always provided by the caller. And the check for the existence of the backbone_gw doesn't provide any additional security check for the deletion of a claim.
--- net/batman-adv/bridge_loop_avoidance.c | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +1 -9
@@ -946,26 +946,18 @@ static bool batadv_handle_unclaim(struct u8 *backbone_addr, u8 *claim_addr, unsigned short vid) { -struct batadv_bla_backbone_gw *backbone_gw; -/* unclaim in any case if it is our own */ if (primary_if &&batadv_compare_eth (backbone_addr, primary_if->net_dev->dev_addr))batadv_bla_send_claim (bat_priv, claim_addr, vid,BATADV_CLAIM_TYPE_UNCLAIM ); - backbone_gw =batadv_backbone_hash_find (bat_priv, backbone_addr, vid); - -if (!backbone_gw) -return true; -/* this must be an UNCLAIM frame */ batadv_dbg (BATADV_DBG_BLA , bat_priv,"%s(): UNCLAIM %pM on vid %d (sent by %pM)...\n" , __func__, - claim_addr,batadv_print_vid (vid), backbone_gw->orig); + claim_addr,batadv_print_vid (vid), backbone_addr);batadv_bla_del_claim (bat_priv, claim_addr, vid); -batadv_backbone_gw_put (backbone_gw);return true; }
Greg Kroah-Hartman
maintainerPATCH 247/798 batman-adv: bla: prevent CRC corruptions after claim flush
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sven Eckelmann <[email protected]>
commit 89f3502ff6878798be96461b2eebd64ba3c3874c upstream.
When batadv_bla_del_backbone_claims() tried to remove all claims of a backbone, it sets the CRC to 0. It assumes that the it had the last reference of the claims because batadv_claim_release() (which runs after the last reference was released), is XORing the crc16 of the claim address with the backbone CRC.
If there would be a parallel holder of any of these references, it could happen that the backbone CRC is (0 ^ crc16(delayed_released_claim)). Which is the wrong starting point for the new claims it may receive when the remote answers the claim request from batadv_bla_send_request().
This reinitializations can be completely dropped to avoid this problem. batadv_claim_release() will take care of fixing the backbone CRC.
--- net/batman-adv/bridge_loop_avoidance.c | 5 ----- 1 file changed, 5 deletions(-)
net/batman-adv/bridge_loop_avoidance.c +0 -5
@@ -324,11 +324,6 @@ batadv_bla_del_backbone_claims(struct ba }spin_unlock_bh (list_lock); } - -/* all claims gone, initialize CRC */ -spin_lock_bh (&backbone_gw->crc_lock); - backbone_gw->crc =BATADV_BLA_CRC_INIT ; -spin_unlock_bh (&backbone_gw->crc_lock); }/**
Greg Kroah-Hartman
maintainerPATCH 248/798 clk: qcom: gcc-msm8916: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit c5339edc6abb601ea10df910ea0b1592fa1016f3 upstream.
According to the APQ8016E TRM, the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-msm8916.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8916.c +3 -2
@@ -1539,9 +1539,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x01004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x01004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .parent_names = (const char *[]){
Greg Kroah-Hartman
maintainerPATCH 249/798 clk: qcom: gcc-msm8939: Fix enable_reg for gcc_blsp1_sleep_clk
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Stephan Gerhold <[email protected]>
commit fc611445b021262b0d4ace6f716a360663816287 upstream.
MSM8939 is similar to MSM8916, where the GCC_BLSP1_SLEEP_CBCR register is read-only and only has the CLK_OFF bit to check if the clock is running. This is a shared vote clock, the correct way to enable it is to vote for BLSP1_SLEEP_CLK_ENA (BIT(9)) in GCC_APCS_CLOCK_BRANCH_ENA_VOTE (0x45004).
--- drivers/clk/qcom/gcc-msm8939.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/clk/qcom/gcc-msm8939.c +3 -2
@@ -1862,9 +1862,10 @@ static struct clk_branch gcc_blsp1_ahb_cstatic struct clk_branch gcc_blsp1_sleep_clk = { .halt_reg =0x01004 , + .halt_check =BRANCH_HALT_VOTED , .clkr = { - .enable_reg =0x01004 , - .enable_mask =BIT (0 ), + .enable_reg =0x45004 , + .enable_mask =BIT (9 ), .hw.init = &(struct clk_init_data ){ .name ="gcc_blsp1_sleep_clk" , .ops = &clk_branch2_ops,
Greg Kroah-Hartman
maintainerPATCH 250/798 i2c: mux: demux-pinctrl: fix OF node leak on kstrdup failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linkai Gong <[email protected]>
commit 62edb8ca0aa44517cc23cfa26cd8a51f15ea92fe upstream.
of_parse_phandle() takes a reference on the parent node. If a later devm_kstrdup() fails, err_rollback only releases nodes for indices 0..i-1, so the current node is leaked.
of_node_put() the current parent before rolling back.
--- drivers/i2c/muxes/i2c-demux-pinctrl.c | 1 + 1 file changed, 1 insertion(+)
drivers/i2c/muxes/i2c-demux-pinctrl.c +1 -0
@@ -245,6 +245,7 @@ static int i2c_demux_pinctrl_probe(struc props[i].value =devm_kstrdup (&pdev->dev,"ok" ,GFP_KERNEL );if (!props[i].name || !props[i].value) { err = -ENOMEM ; +of_node_put (adap_np); goto err_rollback; } props[i].length =3 ;
Greg Kroah-Hartman
maintainerPATCH 251/798 ASoC: cs35l33: drain threaded IRQ before runtime suspend
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit e074c12c428c633e079154301207a6079a208583 upstream.
cs35l33_runtime_suspend() currently switches the codec into regcache_cache_only(true) and powers it down without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l33_irq_thread() can still run after suspend has closed off live register access.
A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1/2 after cache_only has been enabled, ignores the regmap_read() failures, and can still drive the AMP_SHORT_RLS, CAL_ERR_RLS, OTE_RLS, and OTW_RLS release paths.
Use disable_irq() before entering cache_only/power-off so any in-flight threaded handler is drained and no new IRQ thread can run during the suspended state. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only warns if devm_request_threaded_irq() fails, track whether the IRQ was actually installed before disabling or re-enabling it.
--- sound/soc/codecs/cs35l33.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
sound/soc/codecs/cs35l33.c +12 -2
@@ -41,6 +41,7 @@ struct cs35l33_private {struct regmap *regmap;struct gpio_desc *reset_gpio;bool amp_cal; +bool irq_requested;int mclk_int;struct regulator_bulk_data core_supplies[2 ];int num_core_supplies;
@@ -883,6 +884,9 @@ static int __maybe_unused cs35l33_runtim goto err; } +if (cs35l33->irq_requested) +enable_irq (to_i2c_client (dev)->irq); +return 0 ; err:
@@ -902,6 +906,10 @@ static int __maybe_unused cs35l33_runtim/* redo the calibration in next power up */ cs35l33->amp_cal = false; +/* Drain and block the threaded IRQ before cache_only/power-off. */ +if (cs35l33->irq_requested) +disable_irq (to_i2c_client (dev)->irq); +regcache_cache_only (cs35l33->regmap, true);regcache_mark_dirty (cs35l33->regmap); regulator_bulk_disable(cs35l33->num_core_supplies,
@@ -1159,10 +1167,12 @@ static int cs35l33_i2c_probe(struct i2c_ } ret =devm_request_threaded_irq (&i2c_client->dev, i2c_client->irq,NULL , - cs35l33_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , -"cs35l33" , cs35l33); + cs35l33_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , +"cs35l33" , cs35l33);if (ret !=0 )dev_warn (&i2c_client->dev,"Failed to request IRQ: %d\n" , ret); +else + cs35l33->irq_requested = true;/* We could issue !RST or skip it based on AMP topology */ cs35l33->reset_gpio = devm_gpiod_get_optional(&i2c_client->dev,
Greg Kroah-Hartman
maintainerPATCH 252/798 ASoC: cs35l34: drain threaded IRQ before runtime suspend
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Runyu Xiao <[email protected]>
commit 4105a4c0678b2808fc8046b60321b4f1cc7dae75 upstream.
cs35l34_runtime_suspend() currently switches the codec into regcache_cache_only(true), asserts reset low, and powers the device off without first quiescing the threaded IRQ registered by devm_request_threaded_irq(). That leaves a window where cs35l34_irq_thread() can still run after suspend has removed live hardware access.
A running system can reach this during runtime PM while the driver still has critical fault IRQs unmasked. If the threaded handler runs in that window, it reads volatile INT_STATUS_1..4 after cache_only has been enabled, ignores the regmap_read() failures, and can still execute the PROT_RELEASE_CTL release sequence or the BST fault power-down writes.
Use disable_irq() before entering cache_only/reset-low/power-off so any in-flight threaded handler is drained and no new IRQ thread can run while the device is suspended. Re-enable the IRQ only after runtime_resume() has restored live register access with regcache_sync(). Since probe only logs request_threaded_irq() failures and keeps going, track whether the IRQ was actually installed before disabling or re-enabling it.
--- sound/soc/codecs/cs35l34.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
sound/soc/codecs/cs35l34.c +12 -2
@@ -44,6 +44,7 @@ struct cs35l34_private {int num_core_supplies;int mclk_int;bool tdm_mode; +bool irq_requested;struct gpio_desc *reset_gpio;/* Active-low reset GPIO */ };
@@ -1050,10 +1051,12 @@ static int cs35l34_i2c_probe(struct i2c_ } ret =devm_request_threaded_irq (&i2c_client->dev, i2c_client->irq,NULL , - cs35l34_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , -"cs35l34" , cs35l34); + cs35l34_irq_thread,IRQF_ONESHOT |IRQF_TRIGGER_LOW , +"cs35l34" , cs35l34);if (ret !=0 )dev_err (&i2c_client->dev,"Failed to request IRQ: %d\n" , ret); +else + cs35l34->irq_requested = true; cs35l34->reset_gpio =devm_gpiod_get_optional (&i2c_client->dev,"reset" ,GPIOD_OUT_LOW );
@@ -1157,6 +1160,9 @@ static int __maybe_unused cs35l34_runtimdev_err (dev,"Failed to restore register cache\n" ); goto err; } + +if (cs35l34->irq_requested) +enable_irq (to_i2c_client (dev)->irq);return 0 ; err:regcache_cache_only (cs35l34->regmap, true);
@@ -1170,6 +1176,10 @@ static int __maybe_unused cs35l34_runtim {struct cs35l34_private *cs35l34 =dev_get_drvdata (dev); +/* Drain and block the threaded IRQ before cache_only/power-off. */ +if (cs35l34->irq_requested) +disable_irq (to_i2c_client (dev)->irq); +regcache_cache_only (cs35l34->regmap, true);regcache_mark_dirty (cs35l34->regmap);
Greg Kroah-Hartman
maintainerPATCH 253/798 ASoC: fsl: mpc5200-i2s: Free DMA resources on probe failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 3a89ddcf0c3d9a068631e8c24d5c9e81d1e6512a upstream.
mpc5200_audio_dma_create() creates the DMA resources before registering the component. If snd_soc_register_component() fails, the function returns directly and leaves the DMA resources allocated.
Call mpc5200_audio_dma_destroy() before returning from this error path.
--- sound/soc/fsl/mpc5200_psc_i2s.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/fsl/mpc5200_psc_i2s.c +1 -0
@@ -170,6 +170,7 @@ static int psc_i2s_of_probe(struct platf psc_i2s_dai, ARRAY_SIZE(psc_i2s_dai));if (rc !=0 ) {pr_err ("Failed to register DAI\n" ); +mpc5200_audio_dma_destroy (op);return rc; }
Greg Kroah-Hartman
maintainerPATCH 254/798 AsoC: intel: sst: fix PCI device reference leak on probe failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 016f29997ebd29d6ab59c8162ce0e7f73bd1e517 upstream.
intel_sst_probe() takes a reference to the PCI device with pci_dev_get(). If sst_platform_get_resources() fails afterwards, the probe error path cleans up the driver context but does not drop the PCI device reference.
Add a pci_dev_put() error path for failures after pci_dev_get().
--- sound/soc/intel/atom/sst/sst_pci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
sound/soc/intel/atom/sst/sst_pci.c +3 -1
@@ -141,13 +141,15 @@ static int intel_sst_probe(struct pci_de sst_drv_ctx->pci =pci_dev_get (pci); ret =sst_platform_get_resources (sst_drv_ctx);if (ret <0 ) - goto do_free_drv_ctx; + goto do_put_pci;pci_set_drvdata (pci, sst_drv_ctx);sst_configure_runtime_pm (sst_drv_ctx);return ret; +do_put_pci: +pci_dev_put (sst_drv_ctx->pci); do_free_drv_ctx:sst_context_cleanup (sst_drv_ctx);dev_err (sst_drv_ctx->dev,"Probe failed with %d\n" , ret);
Greg Kroah-Hartman
maintainerPATCH 255/798 ASoC: samsung: aries_audio_probe: double of_node_put due to direct assignment without of_node_get
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: WenTao Liang <[email protected]>
commit fb5d1b1c5f8a920ee697545fa6dee16825085717 upstream.
In aries_audio_probe(), aries_dai[0].platforms->of_node is assigned the same pointer as aries_dai[0].cpus->of_node (from of_parse_phandle) without calling of_node_get(). When the sound card is deregistered, the ASoC framework calls of_node_put() on both cpus->of_node and platforms->of_node, causing a double put on the same node and a refcount underflow.
Add of_node_get(aries_dai[0].cpus->of_node) before the assignment.
--- sound/soc/samsung/aries_wm8994.c | 1 + 1 file changed, 1 insertion(+)
sound/soc/samsung/aries_wm8994.c +1 -0
@@ -650,6 +650,7 @@ static int aries_audio_probe(struct plat goto out; } +of_node_get (aries_dai[0 ].cpus->of_node); aries_dai[0 ].platforms->of_node = aries_dai[0 ].cpus->of_node;/* Set CPU of_node for BT DAI */
Greg Kroah-Hartman
maintainerPATCH 256/798 iio: chemical: sgp30: Handle IAQ thread creation failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Linmao Li <[email protected]>
commit 1135d6875d2dbda3f6ec718f3421a6ce4378bd63 upstream.
kthread_run() can fail and return an error pointer, but sgp_probe() stores it and returns success, so the device is registered without its IAQ thread and sgp_remove() later passes the error pointer to kthread_stop(). Return the error from probe instead.
--- drivers/iio/chemical/sgp30.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iio/chemical/sgp30.c +3 -0
@@ -548,6 +548,9 @@ static int sgp_probe(struct i2c_client * data->iaq_thread =kthread_run (sgp_iaq_threadfn, data,"%s-iaq" , data->client->name); +if (IS_ERR (data->iaq_thread)) +return dev_err_probe (dev,PTR_ERR (data->iaq_thread), +"failed to start IAQ thread\n" );return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 257/798 iio: dac: m62332: Fix regulator reference count imbalance
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Erick Henrique <[email protected]>
commit a130404ce0b69ca1438126bd81c1985d3b4d2e6f upstream.
m62332_set_value() enables the Vcc regulator on every write of a non-zero value and disables it on every write of zero, without tracking the channel's current state. Because the regulator is reference counted, changing a channel directly from one non-zero value to another enables it more than once, while a later write of zero disables it only once. The reference count never returns to zero and the regulator is left enabled indefinitely.
Only enable the regulator on the transition from zero to non-zero, and only disable it on the transition from non-zero to zero, using the previously stored channel value to detect the edge. Balance the regulator on the I2C error path so the reference count stays consistent if the write fails.
--- drivers/iio/dac/m62332.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-)
drivers/iio/dac/m62332.c +12 -5
@@ -34,6 +34,7 @@ static int m62332_set_value(struct iio_d {struct m62332_data *data =iio_priv (indio_dev);struct i2c_client *client = data->client; +bool enabling, disabling;u8 outbuf[2 ];int res;
@@ -45,7 +46,10 @@ static int m62332_set_value(struct iio_dmutex_lock (&data->mutex); -if (val) { + enabling = val && !data->raw[channel]; + disabling = !val && data->raw[channel]; + +if (enabling) { res =regulator_enable (data->vcc);if (res) goto out;
@@ -54,14 +58,17 @@ static int m62332_set_value(struct iio_d res =i2c_master_send (client, outbuf,ARRAY_SIZE (outbuf));if (res >=0 && res !=ARRAY_SIZE (outbuf)) res = -EIO ; -if (res <0 ) +if (res <0 ) { +if (enabling) +regulator_disable (data->vcc); goto out; + } - data->raw[channel] = val; - -if (!val) +if (disabling)regulator_disable (data->vcc); + data->raw[channel] = val; +mutex_unlock (&data->mutex);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 258/798 iio: gyro: mpu3050: fix sign of raw angular velocity readings
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit 06fab97602fe400bea843176f485bbac07a668e2 upstream.
The MPU-3050 gyroscope output registers hold 16-bit two's complement values; the angular velocity channels are declared with .sign = 's'. When mpu3050_read_raw() handles IIO_CHAN_INFO_RAW it reads the register via a big-endian regmap_bulk_read() and assigns it with:
*val = be16_to_cpu(raw_val);
be16_to_cpu() yields an unsigned 16-bit quantity, so negative rates (bit 15 set) are reported to userspace as large positive integers (e.g. -1 becomes 65535) instead of the correct negative value.
Cast to s16 before the assignment, matching the temperature channel a few lines above which already handles the sign correctly.
--- drivers/iio/gyro/mpu3050-core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/gyro/mpu3050-core.c +1 -1
@@ -354,7 +354,7 @@ static int mpu3050_read_raw(struct iio_d goto out_read_raw_unlock; } - *val =be16_to_cpu (raw_val); + *val = (s16 )be16_to_cpu (raw_val); ret =IIO_VAL_INT ; goto out_read_raw_unlock;
Greg Kroah-Hartman
maintainerPATCH 259/798 iio: light: cm32181: return zero after writing calibscale
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Giorgi Tchankvetadze <[email protected]>
commit 8756acd30919a3e9f547ea4a1d4b7f7895f4d340 upstream.
The write_raw callback is documented to return 0 on success or a negative error code. However, the IIO_CHAN_INFO_CALIBSCALE case returns 'val' (the user-supplied value) instead of 0.
Fix it by returning 0 on success, matching the behavior of other calibscale implementations in the subsystem.
--- drivers/iio/light/cm32181.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iio/light/cm32181.c +1 -1
@@ -370,7 +370,7 @@ static int cm32181_write_raw(struct iio_switch (mask) {case IIO_CHAN_INFO_CALIBSCALE : cm32181->calibscale = val; -return val; +return 0 ;case IIO_CHAN_INFO_INT_TIME : ret =cm32181_write_als_it (cm32181, val2);return ret;
Greg Kroah-Hartman
maintainerPATCH 260/798 iio: light: gp2ap002: Disable regulators on resume failure
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Laxman Acharya Padhya <[email protected]>
commit a41000ba3a230bed1e422f283486ff8f77fe0d30 upstream.
If enabling VIO fails after VDD has been enabled, runtime resume returns without disabling VDD. Likewise, if device reinitialization fails, both supplies remain enabled. The runtime PM core keeps the device suspended when its resume callback fails, so the supplies must be restored to the suspended state.
Disable the supplies enabled by the callback before returning an error.
--- drivers/iio/light/gp2ap002.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/iio/light/gp2ap002.c +8 -2
@@ -679,7 +679,7 @@ static int __maybe_unused gp2ap002_runti ret =regulator_enable (gp2ap002->vio);if (ret) {dev_err (dev,"failed to enable VIO regulator in resume path\n" ); -return ret; + goto out_disable_vdd; }msleep (20 );
@@ -687,13 +687,19 @@ static int __maybe_unused gp2ap002_runti ret =gp2ap002_init (gp2ap002);if (ret) {dev_err (dev,"re-initialization failed\n" ); -return ret; + goto out_disable_vio; }/* Re-activate the IRQ */ enable_irq (gp2ap002->irq);return 0 ; + +out_disable_vio: +regulator_disable (gp2ap002->vio); +out_disable_vdd: +regulator_disable (gp2ap002->vdd); +return ret; }static const struct dev_pm_ops gp2ap002_dev_pm_ops = {
Greg Kroah-Hartman
maintainerPATCH 261/798 iio: srf04: fix pm_runtime handling on probe error path
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Cong Nguyen <[email protected]>
commit a40b2e7a17f26e38ab054363c9c7cde149588357 upstream.
When pm_runtime_set_active() fails during probe, the driver logs the error and unregisters the IIO device, but then falls through and still calls pm_runtime_enable() before returning the error.
Since probe returns an error, srf04_remove() is never called, so runtime PM is left enabled without a matching pm_runtime_disable(). This leaks the enable and triggers an "Unbalanced pm_runtime_enable!" warning on a subsequent bind of the device.
Return the error right after unregistering the IIO device so that runtime PM is not enabled on the failure path.
--- drivers/iio/proximity/srf04.c | 1 + 1 file changed, 1 insertion(+)
drivers/iio/proximity/srf04.c +1 -0
@@ -336,6 +336,7 @@ static int srf04_probe(struct platform_dif (ret) {dev_err (data->dev,"pm_runtime_set_active: %d\n" , ret);iio_device_unregister (indio_dev); +return ret; }pm_runtime_enable (data->dev);
Greg Kroah-Hartman
maintainerPATCH 262/798 iio: temperature: hid-sensor-temperature: switch to non-devm iio_device_register()
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sanjay Chitroda <[email protected]>
commit 967d066f5334740f656577bc51c381a1bb707b61 upstream.
Avoid using devm_iio_device_register(), as this driver requires explicit error handling and teardown ordering.
With devm_iio_device_register(), IIO device remains registered until the devres cleanup phase. However, driver's remove() callback removes the sensor hub callback and trigger support. This can create a race window where IIO device is still visible and read_raw() requests are issued. These requests might call sensor_hub_input_attr_get_raw_value(), which waits up to 5 seconds for a response from the sensor hub callback that has already been removed.
Add an explicit iio_device_unregister() call in the teardown path to ensure deterministic cleanup, so that userspace can no longer access the device once backend resources begin to be dismantled.
--- drivers/iio/temperature/hid-sensor-temperature.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/iio/temperature/hid-sensor-temperature.c +2 -1
@@ -244,7 +244,7 @@ static int hid_temperature_probe(structif (ret) goto error_remove_trigger; - ret =devm_iio_device_register (indio_dev->dev.parent, indio_dev); + ret =iio_device_register (indio_dev);if (ret) goto error_remove_callback;
@@ -264,6 +264,7 @@ static int hid_temperature_remove(structstruct iio_dev *indio_dev =platform_get_drvdata (pdev);struct temperature_state *temp_st =iio_priv (indio_dev); +iio_device_unregister (indio_dev);sensor_hub_remove_callback (hsdev,HID_USAGE_SENSOR_TEMPERATURE );hid_sensor_remove_trigger (indio_dev, &temp_st->common_attributes);
Greg Kroah-Hartman
maintainerPATCH 263/798 KVM: x86: hyper-v: Clamp stimer deadline to avoid livelock
In reply to Greg Kroah-Hartman5.10-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos López <[email protected]>
commit 0ca49fbd2883cd53d32d85b50feef17fa04d0fbf upstream.
Fix an issue where userspace or the guest can program an Hyper-V synthetic timer to have a deadline in the past via integer overflow, preventing the CPU from making progress and triggering an RCU stall.
Hyper-V's SynIC exposes 4 per-vCPU synthetic timers to the guest, which are emulated by KVM. Each is programmed through the HV_X64_MSR_STIMERi_CONFIG and HV_X64_MSR_STIMERi_COUNT MSRs. Depending on CONFIG, COUNT represents either the absolute expiration time or the period of a periodic timer, both expressed in 100ns ticks. These timers may be set both by the guest (WRMSR) and the host (KVM_SET_MSRS).
When the timer is enabled, stimer_start() translates COUNT to an absolute monotonic deadline and arms an hrtimer. If COUNT is set to a value close to U64_MAX, the deadline calculation can overflow.
ktime_add_ns(ktime_now, 100 * (stimer->exp_time - time_now))
This can result in a CPU livelock. stimer_start() arms the timer via hrtimer_start() with a deadline in the past, which causes it to immediately fire. The stimer callback then raises KVM_RQ_HV_STIMER, with the intention of causing KVM to deliver a synthetic interrupt on the next vCPU guest enter.
Then, once userspace issues KVM_RUN, vcpu_enter_guest() consumes the request, calling kvm_hv_process_stimers(). This would normally disable the timer via stimer_expiration() once the deadline is in the past. However, the deadline comparison is done between the KVM reference counter and stime->exp_time, which is a big value close to U64_MAX, so this never happens for a few thousand years.
kvm_hv_process_timers() then re-arms the timer via stimer_start(), since it was not disabled, which again fires immediately. Before entering the guest, kvm_vcpu_exit_request() checks kvm_request_pending(), which returns true due to the newly raised KVM_REQ_HV_STIMER. Then vcpu_enter_guest() aborts the guest entry, returning early into vcpu_run(), which loops back again into vcpu_enter_guest(), restarting the cycle.
Since there are no manual yields in this loop, a task with SCHED_FIFO may starve RCU grace-period kthreads, which exposes the stalls found by syzcaller:
rcu: INFO: rcu_preempt detected stalls on CPUs/tasks:
rcu: (detected by 1, t=10502 jiffies, g=14269, q=1142 ncpus=2)
rcu: All QSes seen, last rcu_preempt kthread activity 10500 (4294965239-4294954739), jiffies_till_next_fqs=1, root ->qsmask 0x0
rcu: rcu_preempt kthread starved for 10500 jiffies! g14269 f0x2 RCU_GP_WAIT_FQS(5) ->state=0x0 ->cpu=0
rcu: Unless rcu_preempt kthread gets sufficient CPU time, OOM is now expected behavior.
( ... )
Call Trace:
<IRQ>
__run_hrtimer kernel/time/hrtimer.c:1773 [inline]
__hrtimer_run_queues+0x408/0xc30 kernel/time/hrtimer.c:1841
hrtimer_interrupt+0x45b/0xaa0 kernel/time/hrtimer.c:1903
local_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1045 [inline]
__sysvec_apic_timer_interrupt+0x102/0x3e0 arch/x86/kernel/apic/apic.c:1062
instr_sysvec_apic_timer_interrupt arch/x86/kernel/apic/apic.c:1056 [inline]
sysvec_apic_timer_interrupt+0xa1/0xc0 arch/x86/kernel/apic/apic.c:1056
</IRQ>
<TASK>
asm_sysvec_apic_timer_interrupt+0x1a/0x20 arch/x86/include/asm/idtentry.h:697
RIP: 0010:__raw_spin_unlock_irqrestore include/linux/spinlock_api_smp.h:152 [inline]
RIP: 0010:_raw_spin_unlock_irqrestore+0xa8/0x110 kernel/locking/spinlock.c:194
Code: 74 05 e8 0b f4 5f f6 48 c7 44 24 20 00 00 00 00 9c 8f 44 24 20 f6 44 24 21 02 75 4f f7 c3 00 02 00 00 74 01 fb bf 01 00 00 00 <e8> 23 6b 27 f6 65 8b 05 7c 60 5a 07 85 c0 74 40 48 c7 04 24 0e 36
RSP: 0018:ffffc900040a7320 EFLAGS: 00000206
RAX: 5de15cb931505900 RBX: 0000000000000a06 RCX: 5de15cb931505900
RDX: 0000000000000007 RSI: ffffffff8daa9dc3 RDI: 0000000000000001
RBP: ffffc900040a73b0 R08: ffffffff8fc3d077 R09: 1ffffffff1f87a0e
R10: dffffc0000000000 R11: fffffbfff1f87a0f R12: dffffc0000000000
R13: 0000000000000000 R14: ffff8880b8628240 R15: 1ffff92000814e64
hrtimer_start include/linux/hrtimer.h:259 [inline]
stimer_start arch/x86/kvm/hyperv.c:682 [inline]
kvm_hv_process_stimers+0xd0a/0x16a0 arch/x86/kvm/hyperv.c:893
vcpu_enter_guest arch/x86/kvm/x86.c:11193 [inline]
vcpu_run+0x2240/0x76b0 arch/x86/kvm/x86.c:11639
kvm_arch_vcpu_ioctl_run+0x1148/0x1c90 arch/x86/kvm/x86.c:11984
kvm_vcpu_ioctl+0x99a/0xed0 virt/kvm/kvm_main.c:4492
vfs_ioctl fs/ioctl.c:51 [inline]
__do_sys_ioctl fs/ioctl.c:597 [inline]
__se_sys_ioctl+0xfc/0x170 fs/ioctl.c:583
do_syscall_x64 arch/x86/entry/syscall_64.c:63 [inline]
do_syscall_64+0xfa/0xf80 arch/x86/entry/syscall_64.c:94
entry_SYSCALL_64_after_hwframe+0x77/0x7f
RIP: 0033:0x7f635278f749
Code: ff ff c3 66 2e 0f 1f 84 00 00 00 00 00 0f 1f 40 00 48 89 f8 48 89 f7 48 89 d6 48 89 ca 4d 89 c2 4d 89 c8 4c 8b 4c 24 08 0f 05 <48> 3d 01 f0 ff ff 73 01 c3 48 c7 c1 a8 ff ff ff f7 d8 64 89 01 48
RSP: 002b:00007f635365c038 EFLAGS: 00000246 ORIG_RAX: 0000000000000010
RAX: ffffffffffffffda RBX: 00007f63529e5fa0 RCX: 00007f635278f749
RDX: 0000000000000000 RSI: 000000000000ae80 RDI: 0000000000000005
RBP: 00007f6352813f91 R08: 0000000000000000 R09: 0000000000000000
R10: 0000000000000000 R11: 0000000000000246 R12: 0000000000000000
R13: 00007f63529e6038 R14: 00007f63529e5fa0 R15: 00007ffd5b219358
</TASK>Fix this by clamping the deadline computation to KTIME_MAX, which preserves the intent of arming a timer very far in the future. ktime_add_safe() already does this type of clamping, so use it after checking that that multiplying by the 100ns time tick also does not overflow.
--- arch/x86/kvm/hyperv.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-)
arch/x86/kvm/hyperv.c +18 -7
@@ -576,6 +576,18 @@ static enum hrtimer_restart stimer_timer }/* +* Translate a stimer expiry given in 100ns reference ticks into an +* an absolute deadline. Saturates on overflow. +*/ +static ktime_t stimer_add_delta (ktime_t now,u64 delta_100ns) +{ +if (delta_100ns >=KTIME_MAX /100 ) +return KTIME_MAX ; + +return ktime_add_safe (now,100 * delta_100ns); +} + +/* * stimer_start() assumptions: * a) stimer->count is not equal to 0 * b) stimer->config has HV_STIMER_ENABLE flag
@@ -584,6 +596,7 @@ static int stimer_start(struct kvm_vcpu_ {u64 time_now;ktime_t ktime_now; +ktime_t deadline; time_now =get_time_ref_counter (stimer_to_vcpu (stimer)->kvm); ktime_now =ktime_get ();
@@ -606,10 +619,8 @@ static int stimer_start(struct kvm_vcpu_ stimer->index, time_now, stimer->exp_time); -hrtimer_start (&stimer->timer, -ktime_add_ns (ktime_now, -100 * (stimer->exp_time - time_now)), -HRTIMER_MODE_ABS ); + deadline =stimer_add_delta (ktime_now, stimer->exp_time - time_now); +hrtimer_start (&stimer->timer, deadline,HRTIMER_MODE_ABS );return 0 ; } stimer->exp_time = stimer->count;
@@ -628,9 +639,9 @@ static int stimer_start(struct kvm_vcpu_ stimer->index, time_now, stimer->count); -hrtimer_start (&stimer->timer, -ktime_add_ns (ktime_now,100 * (stimer->count - time_now)), -HRTIMER_MODE_ABS ); + deadline =stimer_add_delta (ktime_now, stimer->count - time_now); +hrtimer_start (&stimer->timer, deadline,HRTIMER_MODE_ABS ); +return 0 ; }