6.18.39-rc1 review
Greg Kroah-Hartman
maintainerPATCH 407/480 iommu/amd: Dont split flush for amd_iommu_domain_flush_all()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Weinan Liu <[email protected]>
commit 69fe699afe1afcb730164b86c228483c2da05f94 upstream.
We have observed multiple full invalidations occurring during device detach when we are done using the vfio-device.
blocked_domain_attach_device()
-> detach_device()
-> amd_iommu_domain_flush_all()
-> amd_iommu_domain_flush_pages(..., CMD_INV_IOMMU_ALL_PAGES_ADDRESS)
while (size != 0) {
-> __domain_flush_pages( flush_size /* power of 2 flush_size */)
-> domain_flush_pages_v1()
-> build_inv_iommu_pages()
-> build_inv_address()
}build_inv_address() will trigger a full invalidation if the chunk size > (1 << 51). Consequently, the guest will issue multiple full invalidations for a single call to amd_iommu_domain_flush_all()
Without this patch, we will see 10 time instead of 1 time full invalidations for every amd_iommu_domain_flush_all().
--- drivers/iommu/amd/iommu.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/iommu/amd/iommu.c +2 -1
@@ -1689,7 +1689,8 @@ void amd_iommu_domain_flush_pages(struct {lockdep_assert_held (&domain->lock); -if (likely (!amd_iommu_np_cache)) { +if (likely (!amd_iommu_np_cache) || + size >= (1ULL <<52 )) {__domain_flush_pages (domain, address, size);/* Wait until IOMMU TLB and all device IOTLB flushes are complete */
Greg Kroah-Hartman
maintainerPATCH 408/480 iommufd: Use sizeof(*hdr) instead of sizeof(hdr) in veventq read
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kai Aizen <[email protected]>
commit be93d186ae88a92e7aa77e122d4e661fa57b1e39 upstream.
The bound-check in iommufd_veventq_fops_read() for the normal vEVENT path uses sizeof(hdr) where the surrounding code uses sizeof(*hdr):
if (!vevent_for_lost_events_header(cur) &&
sizeof(hdr) + cur->data_len > count - done) {hdr is declared as struct iommufd_vevent_header *, so sizeof(hdr) evaluates to the size of the pointer. Surrounding code uses sizeof(*hdr) consistently:
if (done >= count || sizeof(*hdr) > count - done) {
...
if (copy_to_user(buf + done, hdr, sizeof(*hdr))) {
...
done += sizeof(*hdr);struct iommufd_vevent_header is currently 8 bytes (two __u32 fields, flags and sequence), so on 64-bit (sizeof(void *) == 8) the two expressions happen to be equal and the check works as intended.
On 32-bit (sizeof(void *) == 4) the check under-counts the header by 4 bytes: a vEVENT whose data_len causes 8 + cur->data_len to exceed count - done while 4 + cur->data_len does not will pass the check, then the loop will copy_to_user 8 bytes of header followed by data_len bytes of payload, writing past the user-supplied buffer.
It is also a latent bug for any future expansion of struct iommufd_vevent_header beyond sizeof(void *) on 64-bit; the check should not depend on the type happening to match the host pointer width.
Use sizeof(*hdr) to match the rest of the function and the actual amount that will be copied.
--- drivers/iommu/iommufd/eventq.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/iommufd/eventq.c +1 -1
@@ -321,7 +321,7 @@ static ssize_t iommufd_veventq_fops_read/* If being a normal vEVENT, validate against the full size */ if (!vevent_for_lost_events_header (cur) && -sizeof (hdr) + cur->data_len > count - done) { +sizeof (*hdr) + cur->data_len > count - done) {iommufd_veventq_deliver_restore (veventq, cur);break ; }
Greg Kroah-Hartman
maintainerPATCH 409/480 iommufd: Fix data_len byte-count vs element-count mismatch
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 85345becfead3255a5f875d4b4d82ea01d926239 upstream.
kzalloc_flex() computes the allocation size. With event_data typed as u64, data_len is interpreted as a u64 element count. Yet, every caller and the read path treat data_len as a byte count. The current code over-allocates by sizeof(u64) and the __counted_by() annotation overstates the length by the same factor.
Re-type event_data as u8. No functional change in user-visible behavior.
--- drivers/iommu/iommufd/iommufd_private.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/iommu/iommufd/iommufd_private.h +1 -1
@@ -599,7 +599,7 @@ struct iommufd_vevent {struct iommufd_vevent_header header;struct list_head node;/* for iommufd_eventq::deliver */ ssize_t data_len; - u64 event_data[] __counted_by(data_len); + u8 event_data[] __counted_by(data_len); };#define vevent_for_lost_events_header (vevent) \
Greg Kroah-Hartman
maintainerPATCH 410/480 iommufd: Set veventq_depth upper bound
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 6ebf2eb46fbd5b40393ff8fbb847ba96925beaff upstream.
iommufd_veventq_alloc() accepts any !0 veventq_depth from userspace, with an upper bound at U32_MAX.
This leaves a vulnerability where userspace can allocate excessively large queues to exhaust kernel memory reserves.
Cap the veventq_depth (maximum number of entries) to 1 << 19, matching the maximum number of entries in the SMMUv3 EVTQ (the largest use case today).
--- drivers/iommu/iommufd/eventq.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/iommu/iommufd/eventq.c +4 -1
@@ -473,6 +473,9 @@ int iommufd_fault_iopf_handler(struct iostatic const struct file_operations iommufd_veventq_fops =INIT_EVENTQ_FOPS (iommufd_veventq_fops_read,NULL ); +/* An arbitrary upper bound for veventq_depth that fits all existing HWs */ +#define VEVENTQ_MAX_DEPTH (1U << 19) +int iommufd_veventq_alloc (struct iommufd_ucmd *ucmd) {struct iommu_veventq_alloc *cmd = ucmd->cmd;
@@ -484,7 +487,7 @@ int iommufd_veventq_alloc(struct iommufdif (cmd->flags || cmd->__reserved || cmd->type ==IOMMU_VEVENTQ_TYPE_DEFAULT )return -EOPNOTSUPP ; -if (!cmd->veventq_depth) +if (!cmd->veventq_depth || cmd->veventq_depth >VEVENTQ_MAX_DEPTH )return -EINVAL ; viommu =iommufd_get_viommu (ucmd, cmd->viommu_id);
Greg Kroah-Hartman
maintainerPATCH 411/480 iommufd: Rewind header length in done if iommufd_veventq_fops_read() fails
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 01e41ad76c12ae5c49ab4ef4fc7dd54e9b8784d6 upstream.
When the first event copy fails, rc = -EFAULT will not be reported as done is set to the length of the copied header.
Rewind it to report rc correctly.
--- drivers/iommu/iommufd/eventq.c | 1 + 1 file changed, 1 insertion(+)
drivers/iommu/iommufd/eventq.c +1 -0
@@ -336,6 +336,7 @@ static ssize_t iommufd_veventq_fops_readif (cur->data_len &©_to_user (buf + done, cur->event_data, cur->data_len)) {iommufd_veventq_deliver_restore (veventq, cur); + done -=sizeof (*hdr); rc = -EFAULT ;break ; }
Greg Kroah-Hartman
maintainerPATCH 412/480 iommufd: Reject invalid read count in iommufd_veventq_fops_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 00203ca8323f9714630408c19a209b52397975e6 upstream.
The read count must be large enough to hold a vEVENT header. For a normal vEVENT, it must also hold the trailing data following the header.
iommufd_veventq_fops_read() does not validate the count, but returns 0 as if the read had succeeded while leaving the pending event in the queue.
Return -EINVAL in both undersize cases.
--- drivers/iommu/iommufd/eventq.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/iommu/iommufd/eventq.c +6 -0
@@ -310,6 +310,9 @@ static ssize_t iommufd_veventq_fops_read(struct file *filep, char __user *buf,if (*ppos)return -ESPIPE ; +/* Minimum read count is a vEVENT header */ +if (count <sizeof (*hdr)) +return -EINVAL ;while ((cur =iommufd_veventq_deliver_fetch (veventq))) {/* Validate the remaining bytes against the header size */
@@ -323,6 +326,9 @@ static ssize_t iommufd_veventq_fops_read(struct file *filep, char __user *buf,if (!vevent_for_lost_events_header (cur) &&sizeof (*hdr) + cur->data_len > count - done) {iommufd_veventq_deliver_restore (veventq, cur); +/* Read count doesn't fit a single normal vEVENT */ +if (done ==0 ) + rc = -EINVAL ;break ; }
Signature · 1 line
2.55.0
Greg Kroah-Hartman
maintainerPATCH 413/480 iommufd: Reject invalid read count in iommufd_fault_fops_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 47916a54eeb2a9e654512ee609f71bd5b29db702 upstream.
The read count must be large enough to hold one fault or a group's faults.
iommufd_fault_fops_read() does not validate the count, but returns 0 as if the read had succeeded while leaving the pending fault in the queue.
Return -EINVAL in the undersize cases.
--- drivers/iommu/iommufd/eventq.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/iommu/iommufd/eventq.c +3 -0
@@ -142,6 +142,9 @@ static ssize_t iommufd_fault_fops_read(sif (done >= count || group->fault_count * fault_size > count - done) {iommufd_fault_deliver_restore (fault, group); +/* Read count doesn't fit the first fault group */ +if (done ==0 ) + rc = -EINVAL ;break ; }
Greg Kroah-Hartman
maintainerPATCH 414/480 iommufd: Break the loop on failure in iommufd_fault_fops_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 172fc8b19825a0f5884c38f2289188284e2d45ee upstream.
On a copy_to_user() failure inside the inner list_for_each_entry, only the inner loop breaks; the outer while re-fetches the just-restored fault group and retries the failing copy_to_user() forever, spinning the reader at 100% CPU with fault->mutex held.
Check rc after the inner loop and break the outer while as well.
--- drivers/iommu/iommufd/eventq.c | 2 ++ 1 file changed, 2 insertions(+)
drivers/iommu/iommufd/eventq.c +2 -0
@@ -168,6 +168,8 @@ static ssize_t iommufd_fault_fops_read(s } done += fault_size; } +if (rc) +break ; }mutex_unlock (&fault->mutex);
Greg Kroah-Hartman
maintainerPATCH 415/480 iommufd: Avoid partial fault group delivery in iommufd_fault_fops_read()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 091ab6d70dc444f56ed14faedbcacfc979f4c613 upstream.
The cookie returned by xa_alloc() in iommufd_fault_fops_read() is per fault group, but the inner copy_to_user() runs per fault inside the group. If a copy fails mid-group, xa_erase clears the cookie and the group is restored to the deliver list, yet done is not rolled back. The function returns the partial byte count, with the successfully copied faults sitting at offsets below done carrying the now-erased cookie. The next read() then re-fetches the group, allocates a fresh cookie, and re-delivers every fault including the ones already copied; userspace sees duplicates carrying the new cookie, and a stale cookie that can never be responded to.
Use a local group_done variable that tracks the per-group progress inside the inner loop, and only commit done = group_done after the inner loop has finished successfully. On a copy_to_user failure the outer break skips the commit, so done remains at its prior start-of-group baseline; the partial bytes already written past done are undefined to userspace per the read(2) contract, and the next read re-delivers the whole group atomically.
--- drivers/iommu/iommufd/eventq.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-)
drivers/iommu/iommufd/eventq.c +5 -2
@@ -139,6 +139,8 @@ static ssize_t iommufd_fault_fops_read(smutex_lock (&fault->mutex);while ((group =iommufd_fault_deliver_fetch (fault))) { +size_t group_done = done; +if (done >= count || group->fault_count * fault_size > count - done) {iommufd_fault_deliver_restore (fault, group);
@@ -160,16 +162,17 @@ static ssize_t iommufd_fault_fops_read(siommufd_compose_fault_message (&iopf->fault, &data, idev, group->cookie); -if (copy_to_user (buf + done, &data, fault_size)) { +if (copy_to_user (buf + group_done, &data, fault_size)) {xa_erase (&fault->response, group->cookie);iommufd_fault_deliver_restore (fault, group); rc = -EFAULT ;break ; } - done += fault_size; + group_done += fault_size; }if (rc)break ; + done = group_done; }mutex_unlock (&fault->mutex);
Greg Kroah-Hartman
maintainerPATCH 416/480 iommufd: Set upper bounds on cache invalidation entry_num and entry_len
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Nicolin Chen <[email protected]>
commit 4d70986002f2f3eaaed89124fb2522bded38b016 upstream.
iommufd_hwpt_invalidate() takes a user-controlled entry_num and entry_len, each bounded only by U32_MAX. An entry_len beyond the kernel's struct size makes the copy helper verify the extra bytes are zero, scanning that excess in one uninterruptible pass; a multi-gigabyte value over zeroed user memory trips the soft-lockup watchdog.
A large entry_num is the other half, driving the backend invalidation loop with no reschedule. The VT-d nested handler, for one, copies each entry and flushes caches per iteration, pinning the CPU on a non-preemptible kernel.
Cap both in the ioctl. entry_len is held under PAGE_SIZE, above any request struct, and entry_num under 1 << 19, the order of a hardware invalidation queue and well beyond any real batch, bounding the per-call loop length.
--- drivers/iommu/iommufd/hw_pagetable.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-)
drivers/iommu/iommufd/hw_pagetable.c +10 -1
@@ -489,6 +489,9 @@ int iommufd_hwpt_get_dirty_bitmap(structreturn rc; } +/* An arbitrary entry_num cap, far above any realistic invalidation batch */ +#define IOMMU_HWPT_INVALIDATE_ENTRY_NUM_MAX (1U << 19) +int iommufd_hwpt_invalidate (struct iommufd_ucmd *ucmd) {struct iommu_hwpt_invalidate *cmd = ucmd->cmd;
@@ -507,7 +510,13 @@ int iommufd_hwpt_invalidate(struct iommu goto out; } -if (cmd->entry_num && (!cmd->data_uptr || !cmd->entry_len)) { +/* +* Bound entry_num and entry_len so a single call cannot pin the CPU; +* entry_len also caps the copy_struct_from_user() trailing-zero scan. +*/ +if (cmd->entry_num && + (!cmd->data_uptr || !cmd->entry_len || cmd->entry_len >PAGE_SIZE || + cmd->entry_num >IOMMU_HWPT_INVALIDATE_ENTRY_NUM_MAX )) { rc = -EINVAL ; goto out; }
Greg Kroah-Hartman
maintainerPATCH 417/480 audit: fix removal of dangling executable rules
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ricardo Robaina <[email protected]>
commit 888a0396e154524f4027f27da84bdbec9eb68916 upstream.
When an audited executable is deleted from the disk, its dentry becomes negative. Any later attempt to delete the associated audit rule will lead to audit_alloc_mark() encountering this negative dentry and immediately aborting, returning -ENOENT.
This early abort prevents the subsystem from allocating the temporary fsnotify mark needed to construct the search key, meaning the kernel cannot find the existing rule in its own lists to delete it. This leaves a dangling rule in memory, resulting in the following error while attempting to delete the rule:
# ./audit-dupe-exe-deadlock.sh No rules Error deleting rule (No such file or directory) There was an error while processing parameters
# auditctl -l -a always,exit -S all -F exe=/tmp/file -F path=/tmp/file -F key=dr
# auditctl -D Error deleting rule (No such file or directory) There was an error while processing parameters
This patch fixes this issue by removing the d_really_is_negative() check. By doing so, a dummy mark can be successfully generated for the deleted path, which allows the audit subsystem to properly match and flush the dangling rule.
--- kernel/audit_fsnotify.c | 4 ---- 1 file changed, 4 deletions(-)
kernel/audit_fsnotify.c +0 -4
@@ -84,10 +84,6 @@ struct audit_fsnotify_mark *audit_alloc_ dentry =kern_path_parent (pathname, &path);if (IS_ERR (dentry))return ERR_CAST (dentry);/* returning an error */ -if (d_really_is_negative (dentry)) { - audit_mark =ERR_PTR (-ENOENT ); - goto out; - } audit_mark =kzalloc (sizeof (*audit_mark),GFP_KERNEL );if (unlikely (!audit_mark)) {
Greg Kroah-Hartman
maintainerPATCH 418/480 landlock: Set audit_net.sk for socket access checks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mickaël Salaün <[email protected]>
commit d936e1a9170f9cadaa5f37586b1dfe6f20f98799 upstream.
Set audit_net.sk in current_check_access_socket() to provide the socket object to audit_log_lsm_data(). This makes Landlock consistent with AppArmor, which always sets .sk for socket operations, and with SELinux's generic socket permission checks.
The socket's local and foreign address information (laddr, lport, faddr, fport) is logged by the shared lsm_audit.c infrastructure when the socket has bound or connected state. Fields with zero values are suppressed by print_ipv4_addr()/print_ipv6_addr(), so the audit output is unchanged for the common case of bind denials on unbound sockets. For connect denials after a prior bind, the bound local address (laddr, lport) appears before the existing sockaddr fields (daddr, dest).
No existing fields are removed or reordered, and the new field names (laddr, lport, faddr, fport) are standard audit fields already emitted by other LSMs through the same lsm_audit.c code path.
Add a connect_tcp_bound audit test that binds to an allowed port and then connects to a denied one, verifying that the denial record reports laddr/lport from the bound socket in addition to the connect destination.
--- security/landlock/net.c | 1 tools/testing/selftests/landlock/net_test.c | 62 ++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+)
security/landlock/net.c +1 -0
@@ -199,6 +199,7 @@ static int current_check_access_socket(sreturn 0 ; audit_net.family = address->sa_family; + audit_net.sk = sock->sk; landlock_log_denial(subject, &(struct landlock_request){ .type = LANDLOCK_REQUEST_NET_ACCESS,
tools/testing/selftests/landlock/net_test.c +62 -0
66 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 419/480 selftests/landlock: Filter dealloc records in audit_count_records()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mickaël Salaün <[email protected]>
commit 26679fad81a471428707d2dd7b0418204c52b7e4 upstream.
audit_count_records() counts both AUDIT_LANDLOCK_DOMAIN allocation and deallocation records in records.domain . Domain deallocation is tied to asynchronous credential freeing via kworker threads (landlock_put_ruleset_deferred), so the dealloc record can arrive after the drain in audit_init() and after the preceding audit_match_record() call. This causes flaky failures in tests that assert an exact records.domain count: a stale dealloc record from a previous test's domain inflates the count by one.
Observed on x86_64 under build configurations that delay the kworker firing the dealloc callback (e.g. coverage instrumentation): the audit_layout1 tests in fs_test.c intermittently saw records.domain == 2 where 1 was expected. The fix is in the shared helper, so those existing checks become robust without needing a fs_test.c edit.
Filter audit_count_records() with a regex to skip records containing deallocation status. The remaining domain records (allocation, emitted synchronously during landlock_log_denial()) are deterministic. Deallocation records are already tested explicitly via matches_log_domain_deallocated() in audit_test.c, which uses its own domain-ID-based filtering and longer timeout.
With this filter in place, re-add the records.domain == 0 checks that were removed in commit 3647a4977fb7 ("selftests/landlock: Drain stale audit records on init") as a workaround for this race.
Cc: Günther Noack <[email protected]>
Cc: [email protected]
Depends-on: 07c2572a8757 ("selftests/landlock: Skip stale records in audit_match_record()")
--- tools/testing/selftests/landlock/audit.h | 39 +++++++---- tools/testing/selftests/landlock/audit_test.c | 2 tools/testing/selftests/landlock/ptrace_test.c | 1 tools/testing/selftests/landlock/scoped_abstract_unix_test.c | 1 4 files changed, 30 insertions(+), 13 deletions(-)
tools/testing/selftests/landlock/audit.h +26 -13
@@ -381,18 +381,24 @@ struct audit_records { };/* -* WARNING: Do not assert records.domain == 0 without a preceding -* audit_match_record() call. Domain deallocation records are emitted -* asynchronously from kworker threads and can arrive after the drain in -* audit_init(), corrupting the domain count. A preceding audit_match_record() -* call consumes stale records while scanning, making the assertion safe in -* practice because stale deallocation records arrive before the expected access -* records. +* Counts remaining audit records by type, skipping domain deallocation records. +* Deallocation records are emitted asynchronously from kworker threads after a +* previous test's child has exited, so they can arrive after the drain in +* audit_init() and after the preceding audit_match_record() call. Allocation +* records are emitted synchronously during landlock_log_denial() in the current +* test's syscall context, so only those are counted in records->domain. */ static int audit_count_records (int audit_fd,struct audit_records *records) { +static const char dealloc_pattern[] =REGEX_LANDLOCK_PREFIX +" status=deallocated " ;struct audit_message msg; -int err; +regex_t dealloc_re; +int ret, err =0 ; + + ret =regcomp (&dealloc_re, dealloc_pattern,0 ); +if (ret) +return -ENOMEM ; records->access =0 ; records->domain =0 ;
@@ -402,9 +408,8 @@ static int audit_count_records(int audit err =audit_recv (audit_fd, &msg);if (err) {if (err == -EAGAIN ) -return 0 ; -else -return err; + err =0 ; +break ; }switch (msg.header.nlmsg_type) {
@@ -412,12 +417,20 @@ static int audit_count_records(int audit records->access++;break ;case AUDIT_LANDLOCK_DOMAIN : - records->domain++; + ret =regexec (&dealloc_re, msg.data,0 ,NULL ,0 ); +if (ret ==REG_NOMATCH ) { + records->domain++; + }else if (ret !=0 ) { + err = -EIO ; + goto out; + }break ; } }while (true); -return 0 ; +out: +regfree (&dealloc_re); +return err; }static int audit_init (void )
tools/testing/selftests/landlock/audit_test.c +2 -0
@@ -497,6 +497,7 @@ TEST_F(audit_flags, signal) }else {EXPECT_EQ (1 , records.access); } +EXPECT_EQ (0 , records.domain);/* Updates filter rules to match the drop record. */ set_cap (_metadata,CAP_AUDIT_CONTROL );
@@ -684,6 +685,7 @@ TEST_F(audit_exec, signal_and_open)/* Tests that there was no denial until now. */ EXPECT_EQ (0 ,audit_count_records (self->audit_fd, &records));EXPECT_EQ (0 , records.access); +EXPECT_EQ (0 , records.domain);/* * Wait for the child to do a first denied action by layer1 and
tools/testing/selftests/landlock/ptrace_test.c +1 -0
@@ -486,6 +486,7 @@ TEST_F(audit, trace)/* Makes sure there is no superfluous logged records. */ EXPECT_EQ (0 ,audit_count_records (self->audit_fd, &records));EXPECT_EQ (0 , records.access); +EXPECT_EQ (0 , records.domain); yama_ptrace_scope =get_yama_ptrace_scope ();ASSERT_LE (0 , yama_ptrace_scope);
tools/testing/selftests/landlock/scoped_abstract_unix_test.c +1 -0
@@ -312,6 +312,7 @@ TEST_F(scoped_audit, connect_to_child)/* Makes sure there is no superfluous logged records. */ EXPECT_EQ (0 ,audit_count_records (self->audit_fd, &records));EXPECT_EQ (0 , records.access); +EXPECT_EQ (0 , records.domain);ASSERT_EQ (0 ,pipe2 (pipe_child,O_CLOEXEC ));ASSERT_EQ (0 ,pipe2 (pipe_parent,O_CLOEXEC ));
Greg Kroah-Hartman
maintainerPATCH 420/480 KVM: arm64: nv: Avoid dereferencing NULL VNCR pseudo-TLB
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Marc Zyngier <[email protected]>
commit 4be6cbeb93d26994bd1827ddbce391e3c4395c8f upstream.
VNCR TLB invalidation occurs from MMU notifiers or TLBI instructions, and either can race against a vcpu not being onlined yet (no pseudo-TLB allocated). Similarly, the TLB might be invalid, and the invalidation should be skipped in this case.
Both kvm_invalidate_vncr_ipa() and kvm_invalidate_vncr_va() are expected to perform the same checks, except that the latter doesn't check for the allocation and blindly dereferences the pointer.
Solve this by introducing a new iterator built on top of the usual kvm_for_each_vcpu() that checks for both of the above conditions, and convert the two users to it.
--- arch/arm64/kvm/nested.c | 36 +++++++++++++++--------------------- 1 file changed, 15 insertions(+), 21 deletions(-)
arch/arm64/kvm/nested.c +15 -21
@@ -824,9 +824,21 @@ static void invalidate_vncr(struct vncr_clear_fixmap (vncr_fixmap (vt->cpu)); } +/* +* VNCR TLB invalidation occurs from MMU notifiers or TLBI instructions, and +* either can race against a vcpu not being onlined yet (no pseudo-TLB +* allocated). Similarly, the TLB might be invalid. Skip those, as they +* obviously don't participate in the invalidation at this stage. +*/ +#define kvm_for_each_vncr_tlb (idx, vcpup, tlbp, kvm) \ + kvm_for_each_vcpu(idx, vcpup, kvm) \ + if (((tlbp) = vcpup->arch.vncr_tlb) && \ + (tlbp)->valid) +static void kvm_invalidate_vncr_ipa (struct kvm *kvm,u64 start,u64 end) {struct kvm_vcpu *vcpu; +struct vncr_tlb *vt;unsigned long i;lockdep_assert_held_write (&kvm->mmu_lock);
@@ -834,24 +846,9 @@ static void kvm_invalidate_vncr_ipa(struif (!kvm_has_feat (kvm,ID_AA64MMFR4_EL1 , NV_frac,NV2_ONLY ))return ; -kvm_for_each_vcpu (i, vcpu, kvm) { -struct vncr_tlb *vt = vcpu->arch.vncr_tlb; +kvm_for_each_vncr_tlb (i, vcpu, vt, kvm) {u64 ipa_start, ipa_end, ipa_size; -/* -* Careful here: We end-up here from an MMU notifier, -* and this can race against a vcpu not being onlined -* yet, without the pseudo-TLB being allocated. -* -* Skip those, as they obviously don't participate in -* the invalidation at this stage. -*/ -if (!vt) -continue ; - -if (!vt->valid) -continue ; - ipa_size =ttl_to_size (pgshift_level_to_ttl (vt->wi.pgshift, vt->wr.level)); ipa_start = vt->wr.pa & ~(ipa_size -1 );
@@ -881,17 +878,14 @@ static void invalidate_vncr_va(struct kv struct s1e2_tlbi_scope *scope) {struct kvm_vcpu *vcpu; +struct vncr_tlb *vt;unsigned long i;lockdep_assert_held_write (&kvm->mmu_lock); -kvm_for_each_vcpu (i, vcpu, kvm) { -struct vncr_tlb *vt = vcpu->arch.vncr_tlb; +kvm_for_each_vncr_tlb (i, vcpu, vt, kvm) {u64 va_start, va_end, va_size; -if (!vt->valid) -continue ; - va_size =ttl_to_size (pgshift_level_to_ttl (vt->wi.pgshift, vt->wr.level)); va_start = vt->gva & ~(va_size -1 );
Greg Kroah-Hartman
maintainerPATCH 421/480 LoongArch: KVM: Add missing slots_lock for device register/unregister
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zeng Chi <[email protected]>
commit aeded601d6aceb57cdda4b2701d2ee00c43a8b69 upstream.
kvm_io_bus_register_dev() and kvm_io_bus_unregister_dev() should be called under kvm->slots_lock. The unregister calls in ipi.c, eiointc.c and pch_pic.c were also missing this protection. Add it to match the register side.
--- arch/loongarch/kvm/intc/eiointc.c | 6 ++++++ arch/loongarch/kvm/intc/ipi.c | 2 ++ arch/loongarch/kvm/intc/pch_pic.c | 2 ++ 3 files changed, 10 insertions(+)
arch/loongarch/kvm/intc/eiointc.c +6 -0
@@ -654,10 +654,14 @@ static int kvm_eiointc_create(struct kvm device = &s->device_vext;kvm_iodevice_init (device, &kvm_eiointc_virt_ops); +mutex_lock (&kvm->slots_lock); ret =kvm_io_bus_register_dev (kvm,KVM_IOCSR_BUS ,EIOINTC_VIRT_BASE ,EIOINTC_VIRT_SIZE , device); +mutex_unlock (&kvm->slots_lock);if (ret <0 ) { +mutex_lock (&kvm->slots_lock);kvm_io_bus_unregister_dev (kvm,KVM_IOCSR_BUS , &s->device); +mutex_unlock (&kvm->slots_lock);kfree (s);return ret; }
@@ -676,8 +680,10 @@ static void kvm_eiointc_destroy(struct k kvm = dev->kvm; eiointc = kvm->arch.eiointc; +mutex_lock (&kvm->slots_lock);kvm_io_bus_unregister_dev (kvm,KVM_IOCSR_BUS , &eiointc->device);kvm_io_bus_unregister_dev (kvm,KVM_IOCSR_BUS , &eiointc->device_vext); +mutex_unlock (&kvm->slots_lock);kfree (eiointc);kfree (dev); }
arch/loongarch/kvm/intc/ipi.c +2 -0
@@ -457,7 +457,9 @@ static void kvm_ipi_destroy(struct kvm_d kvm = dev->kvm; ipi = kvm->arch.ipi; +mutex_lock (&kvm->slots_lock);kvm_io_bus_unregister_dev (kvm,KVM_IOCSR_BUS , &ipi->device); +mutex_unlock (&kvm->slots_lock);kfree (ipi);kfree (dev); }
arch/loongarch/kvm/intc/pch_pic.c +2 -0
@@ -473,7 +473,9 @@ static void kvm_pch_pic_destroy(struct k kvm = dev->kvm; s = kvm->arch.pch_pic;/* unregister pch pic device and free it's memory */ +mutex_lock (&kvm->slots_lock);kvm_io_bus_unregister_dev (kvm,KVM_MMIO_BUS , &s->device); +mutex_unlock (&kvm->slots_lock);kfree (s);kfree (dev); }
Greg Kroah-Hartman
maintainerPATCH 422/480 KVM: arm64: Clear __hyp_running_vcpu when flushing the pKVM hyp vCPU
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Hyunwoo Kim <[email protected]>
commit e8042f6e1d7befb2fb6b10a75918642bcd0acf9a upstream.
flush_hyp_vcpu() copies the host vCPU context into the hyp's private vCPU on every run. ctxt_to_vcpu() expects a guest context to have a NULL __hyp_running_vcpu, which is only ever set on the host context, so that it resolves the vCPU via container_of(). While this is generally the case, flush_hyp_vcpu() copies the context verbatim and does not enforce this, so a value provided by the host is dereferenced at EL2 (host -> EL2).
Fix by clearing __hyp_running_vcpu after the copy.
--- arch/arm64/kvm/hyp/nvhe/hyp-main.c | 3 +++ 1 file changed, 3 insertions(+)
arch/arm64/kvm/hyp/nvhe/hyp-main.c +3 -0
@@ -126,6 +126,9 @@ static void flush_hyp_vcpu(struct pkvm_h hyp_vcpu->vcpu.arch.ctxt = host_vcpu->arch.ctxt; +/* __hyp_running_vcpu must be NULL in a guest context. */ + hyp_vcpu->vcpu.arch.ctxt.__hyp_running_vcpu =NULL ; + hyp_vcpu->vcpu.arch.mdcr_el2 = host_vcpu->arch.mdcr_el2; hyp_vcpu->vcpu.arch.hcr_el2 &= ~(HCR_TWI |HCR_TWE ); hyp_vcpu->vcpu.arch.hcr_el2 |= READ_ONCE(host_vcpu->arch.hcr_el2) &
Greg Kroah-Hartman
maintainerPATCH 423/480 KVM: SVM: Disable x2AVIC RDMSR interception for MSRs KVM actually supports
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 7f4b7092d9a173a4271e28c0ed1fc235994e309b upstream.
When toggling x2AVIC on/off, use KVM's curated mask of x2APIC MSRs that can/should be passed through to the guest (or not) when 2AVIC is enabled. Using the effective list provided by the local APIC emulation fixes multiple (classes of) bugs, as the existing hand-coded list of MSRs is wrong on multiple fronts:
- ARBPRI isn't supported by KVM, isn't accelerated by AVIC (for read or write), and its #VMEXIT is fault-like, i.e. requires decoding the instruction. Disabling interception is nonsensical and suboptimal.
- DFR and ICR2 aren't supported by x2APIC and so don't need their intercepts disabled for performance reasons. While the #GP due to x2APIC being abled has higher priority than the trap-like #VMEXIT, disabling interception of unsupported MSRs is confusing and unnecessary.
- RRR is completely unsupported.
- AVIC currently fails to pass through the "range of vectors" registers, IRR, ISR, and TMR, as e.g. X2APIC_MSR(APIC_IRR) only affects IRR0, and thus only disables intercept for vectors 31:0 (which are the *least* interesting registers).
- TMCCT (the current APIC timer count) isn't accelerated by hardware, and generates a fault-like AVIC_UNACCELERATED_ACCESS #VMEXIT, i.e. requires KVM to decode the instruction to figure out what the guest was trying to access. Note, the only reason this isn't a fatal bug is that the AVIC architecture had the foresight to guard against buggy hypervisors. E.g. if hardware simply read from the virtual APIC page, the guest would get garbage (because the timer is emulated in software).
--- arch/x86/kvm/svm/avic.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
arch/x86/kvm/svm/avic.c +11 -2
@@ -111,6 +111,9 @@ static bool x2avic_enabled;static void avic_set_x2apic_msr_interception (struct vcpu_svm *svm,bool intercept) { +struct kvm_vcpu *vcpu = &svm->vcpu; +u64 rd_regs; +static const u32 x2avic_passthrough_msrs[] = {X2APIC_MSR (APIC_ID ),X2APIC_MSR (APIC_LVR ),
@@ -151,9 +154,15 @@ static void avic_set_x2apic_msr_intercepif (!x2avic_enabled)return ; + rd_regs =kvm_x2apic_disable_read_intercept_reg_mask (vcpu); + +for_each_set_bit (i, (unsigned long *)&rd_regs,BITS_PER_TYPE (rd_regs)) +svm_set_intercept_for_msr (vcpu,APIC_BASE_MSR + i, +MSR_TYPE_R , intercept); +for (i =0 ; i <ARRAY_SIZE (x2avic_passthrough_msrs); i++) -svm_set_intercept_for_msr (&svm->vcpu, x2avic_passthrough_msrs[i], -MSR_TYPE_RW , intercept); +svm_set_intercept_for_msr (vcpu, x2avic_passthrough_msrs[i], +MSR_TYPE_W , intercept); svm->x2avic_msrs_intercepted = intercept; }
Greg Kroah-Hartman
maintainerPATCH 424/480 KVM: SVM: Only disable x2AVIC WRMSR interception for MSRs that are accelerated
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 8c63179d975f2029c948ecce622f72af616dbff7 upstream.
When x2AVIC is enabled, disable WRMSR interception only for MSRs that are actually accelerated by hardware. Disabling interception for MSRs that aren't accelerated is functionally "fine", and in some cases a weird "win" for performance, but only for cases that should never be triggered by a well-behaved VM (writes to read-only registers; the #GP will typically occur in the guest without taking a #VMEXIT, even for fault-like exits).
But overall, disabling interception for MSRs that aren't accelerated is at best confusing and unintuitive, and at worst introduces avoidable risk, as the APM's documentation is imperfect and contradictory. The table in "15.29.3.1 Virtual APIC Register Accesses" of simply states that such writes generate exits, where as "Section 15.29.10 x2AVIC" says:
x2APIC MSR intercept checks and access checks have higher priority than AVIC access permission checks.
CPU behavior follows the latter (which makes perfect sense), but all in all there's simply no reason to disable interception just to make a #GP faster.
Note, the set of MSRs that are passed through for write is identical to VMX's set when IPI virtualization is enabled. This is not a coincidence, and is another motiviating factor for cleaning up the intercepts, as x2AVIC is functionally equivalent to APICv+IPIv.
--- arch/x86/kvm/svm/avic.c | 40 ++++------------------------------------ 1 file changed, 4 insertions(+), 36 deletions(-)
arch/x86/kvm/svm/avic.c +4 -36
@@ -113,39 +113,6 @@ static void avic_set_x2apic_msr_intercep {struct kvm_vcpu *vcpu = &svm->vcpu;u64 rd_regs; - -static const u32 x2avic_passthrough_msrs[] = { -X2APIC_MSR (APIC_ID ), -X2APIC_MSR (APIC_LVR ), -X2APIC_MSR (APIC_TASKPRI ), -X2APIC_MSR (APIC_ARBPRI ), -X2APIC_MSR (APIC_PROCPRI ), -X2APIC_MSR (APIC_EOI ), -X2APIC_MSR (APIC_RRR ), -X2APIC_MSR (APIC_LDR ), -X2APIC_MSR (APIC_DFR ), -X2APIC_MSR (APIC_SPIV ), -X2APIC_MSR (APIC_ISR ), -X2APIC_MSR (APIC_TMR ), -X2APIC_MSR (APIC_IRR ), -X2APIC_MSR (APIC_ESR ), -X2APIC_MSR (APIC_ICR ), -X2APIC_MSR (APIC_ICR2 ), - -/* -* Note! Always intercept LVTT, as TSC-deadline timer mode -* isn't virtualized by hardware, and the CPU will generate a -* #GP instead of a #VMEXIT. -*/ -X2APIC_MSR (APIC_LVTTHMR ), -X2APIC_MSR (APIC_LVTPC ), -X2APIC_MSR (APIC_LVT0 ), -X2APIC_MSR (APIC_LVT1 ), -X2APIC_MSR (APIC_LVTERR ), -X2APIC_MSR (APIC_TMICT ), -X2APIC_MSR (APIC_TMCCT ), -X2APIC_MSR (APIC_TDCR ), - };int i;if (intercept == svm->x2avic_msrs_intercepted)
@@ -160,9 +127,10 @@ static void avic_set_x2apic_msr_intercepsvm_set_intercept_for_msr (vcpu,APIC_BASE_MSR + i,MSR_TYPE_R , intercept); -for (i =0 ; i <ARRAY_SIZE (x2avic_passthrough_msrs); i++) -svm_set_intercept_for_msr (vcpu, x2avic_passthrough_msrs[i], -MSR_TYPE_W , intercept); +svm_set_intercept_for_msr (vcpu,X2APIC_MSR (APIC_TASKPRI ),MSR_TYPE_W , intercept); +svm_set_intercept_for_msr (vcpu,X2APIC_MSR (APIC_EOI ),MSR_TYPE_W , intercept); +svm_set_intercept_for_msr (vcpu,X2APIC_MSR (APIC_SELF_IPI ),MSR_TYPE_W , intercept); +svm_set_intercept_for_msr (vcpu,X2APIC_MSR (APIC_ICR ),MSR_TYPE_W , intercept); svm->x2avic_msrs_intercepted = intercept; }
Greg Kroah-Hartman
maintainerPATCH 425/480 KVM: VMX: Refresh GUEST_PENDING_DBG_EXCEPTIONS.BS on all injected #DBs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit c5bad4fa2d5dfd8c25140051a9807eba387a19b8 upstream.
Move KVM's stuffing of GUEST_PENDING_DBG_EXCEPTIONS.BS when RFLAGS.TF=1 and MOV/POP SS or STI blocking is active into the exception injection code so that KVM fixes up the VMCS for all injected #DBs, not only those that are reflected back into the guest after #DB interception. E.g. if KVM queues a #DB in the emulator, or more importantly if userspace does save/restore exactly on the #DB+shadow boundary, then KVM needs to massage the VMCS to avoid the VM-Entry consistency check.
Opportunistically update the wording of the comment to describe the behavior as a workaround of flawed CPU behavior/architecture, to make it clear that the *only* thing KVM is doing is fudging around a consistency check. Per the SDM:
There are no pending debug exceptions after VM entry if any of the following are true:
* The VM entry is vectoring with one of the following interruption
types: external interrupt, non-maskable interrupt (NMI), hardware exception, or privileged software exception.
I.e. forcing GUEST_PENDING_DBG_EXCEPTIONS.BS does *not* impact guest- visible behavior.
--- arch/x86/kvm/vmx/vmx.c | 35 ++++++++++++++++++----------------- 1 file changed, 18 insertions(+), 17 deletions(-)
arch/x86/kvm/vmx/vmx.c +18 -17
@@ -1790,6 +1790,24 @@ void vmx_inject_exception(struct kvm_vcpu32 intr_info = ex->vector |INTR_INFO_VALID_MASK ;struct vcpu_vmx *vmx =to_vmx (vcpu); +/* +* When injecting a #DB, single-stepping is enabled in RFLAGS, and STI +* or MOV-SS blocking is active, set vmcs.PENDING_DBG_EXCEPTIONS.BS to +* prevent a false positive from VM-Entry consistency check. VM-Entry +* asserts that a single-step #DB _must_ be pending in this scenario, +* as the previous instruction cannot have toggled RFLAGS.TF 0=>1 +* (because STI and POP/MOV don't modify RFLAGS), therefore the one +* instruction delay when activating single-step breakpoints must have +* already expired. However, the CPU isn't smart enough to peek at +* vmcs.VM_ENTRY_INTR_INFO_FIELD and so doesn't realize that yes, there +* is indeed a #DB pending/imminent. +*/ +if (ex->vector ==DB_VECTOR && + (vmx_get_rflags (vcpu) &X86_EFLAGS_TF ) && +vmx_get_interrupt_shadow (vcpu)) +vmcs_writel (GUEST_PENDING_DBG_EXCEPTIONS , +vmcs_readl (GUEST_PENDING_DBG_EXCEPTIONS ) |DR6_BS ); +kvm_deliver_exception_payload (vcpu, ex);if (ex->has_error_code) {
@@ -5287,26 +5305,9 @@ static int handle_exception_nmi(struct k* avoid single-step #DB and MTF updates, as ICEBP is * higher priority. Note, skipping ICEBP still clears * STI and MOVSS blocking. -* -* For all other #DBs, set vmcs.PENDING_DBG_EXCEPTIONS.BS -* if single-step is enabled in RFLAGS and STI or MOVSS -* blocking is active, as the CPU doesn't set the bit -* on VM-Exit due to #DB interception. VM-Entry has a -* consistency check that a single-step #DB is pending -* in this scenario as the previous instruction cannot -* have toggled RFLAGS.TF 0=>1 (because STI and POP/MOV -* don't modify RFLAGS), therefore the one instruction -* delay when activating single-step breakpoints must -* have already expired. Note, the CPU sets/clears BS -* as appropriate for all other VM-Exits types. */ if (is_icebp (intr_info))WARN_ON (!skip_emulated_instruction (vcpu)); -else if ((vmx_get_rflags (vcpu) &X86_EFLAGS_TF ) && - (vmcs_read32 (GUEST_INTERRUPTIBILITY_INFO ) & - (GUEST_INTR_STATE_STI |GUEST_INTR_STATE_MOV_SS ))) -vmcs_writel (GUEST_PENDING_DBG_EXCEPTIONS , -vmcs_readl (GUEST_PENDING_DBG_EXCEPTIONS ) |DR6_BS );kvm_queue_exception_p (vcpu,DB_VECTOR , dr6);return 1 ;
Greg Kroah-Hartman
maintainerPATCH 426/480 KVM: VMX: Handle bad values on proxied writes to LBR MSRs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xuanqing Shi <[email protected]>
commit ca674df13b195eb6d124ab059799d4e03fa40624 upstream.
Use the "safe" WRMSR API when writing LBRs on behalf of the guest (or host userspace), and propagate any errors back to the instigator, as the value being written is untrusted. E.g. if the guest (or host userspace) attempts to set reserved bits in LBR_SELECT, then KVM needs to return an error, and not WARN on the bad value.
Continue using the "unsafe" version of RDMSR, as it should be impossible to reach the helper with a completely bogus MSR, i.e. WARNing on RDMSR failure is very desirable, e.g. to make KVM bugs more visible.
unchecked MSR access error: WRMSR to 0x1c8 (tried to write 0x0000000000004000)
Call Trace: intel_pmu_set_msr+0x4e0/0x7f0 [kvm_intel] kvm_pmu_set_msr+0x17e/0x1c0 [kvm] kvm_set_msr_common+0xc76/0x1440 [kvm] vmx_set_msr+0x5e6/0x1570 [kvm_intel] kvm_emulate_wrmsr+0x54/0x1d0 [kvm] vmx_handle_exit+0x7fc/0x970 [kvm_intel]
--- arch/x86/kvm/vmx/pmu_intel.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-)
arch/x86/kvm/vmx/pmu_intel.c +4 -2
@@ -320,13 +320,15 @@ static bool intel_pmu_handle_lbr_msrs_ac*/ local_irq_disable ();if (lbr_desc->event->state ==PERF_EVENT_STATE_ACTIVE ) { +int err =0 ; +if (read)rdmsrq (index, msr_info->data);else -wrmsrq (index, msr_info->data); + err =wrmsrq_safe (index, msr_info->data);__set_bit (INTEL_PMC_IDX_FIXED_VLBR ,vcpu_to_pmu (vcpu)->pmc_in_use);local_irq_enable (); -return true; +return !err; }clear_bit (INTEL_PMC_IDX_FIXED_VLBR ,vcpu_to_pmu (vcpu)->pmc_in_use);local_irq_enable ();
Greg Kroah-Hartman
maintainerPATCH 427/480 KVM: x86: Ensure vendors exit handler runs before fastpath userspace exits
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 0ffedf43910e44b76c2c1db4e9fbf12b268190c1 upstream.
Move the handling of fastpath userspace exits into vendor code to ensure KVM runs vendor specific operations that need to run before userspace gains control of the vCPU. E.g. for VMX (and soon to be for SVM as well), KVM needs to flush the PML buffer prior to exiting to userspace, otherwise any memory written by the final KVM_RUN might never be flagged as dirty.
Note, waiting to snapshot CR0 and CR3 until svm_handle_exit() is flawed in general, as that risks consuming stale state in a fastpath handler. That will be addressed in a future change.
--- arch/x86/kvm/svm/svm.c | 3 +++ arch/x86/kvm/vmx/vmx.c | 3 +++ arch/x86/kvm/x86.c | 3 --- 3 files changed, 6 insertions(+), 3 deletions(-)
arch/x86/kvm/svm/svm.c +3 -0
@@ -3569,6 +3569,9 @@ static int svm_handle_exit(struct kvm_vc vcpu->arch.cr3 = svm->vmcb->save.cr3; } +if (unlikely (exit_fastpath ==EXIT_FASTPATH_EXIT_USERSPACE )) +return 0 ; +if (is_guest_mode (vcpu)) {int vmexit;
arch/x86/kvm/vmx/vmx.c +3 -0
@@ -6499,6 +6499,9 @@ static int __vmx_handle_exit(struct kvm_if (enable_pml && !is_guest_mode (vcpu))vmx_flush_pml_buffer (vcpu); +if (unlikely (exit_fastpath ==EXIT_FASTPATH_EXIT_USERSPACE )) +return 0 ; +/* * KVM should never reach this point with a pending nested VM-Enter. * More specifically, short-circuiting VM-Entry to emulate L2 due to
arch/x86/kvm/x86.c +0 -3
@@ -11498,9 +11498,6 @@ static int vcpu_enter_guest(struct kvm_vif (vcpu->arch.apic_attention)kvm_lapic_sync_from_vapic (vcpu); -if (unlikely (exit_fastpath ==EXIT_FASTPATH_EXIT_USERSPACE )) -return 0 ; - r =kvm_x86_call (handle_exit)(vcpu, exit_fastpath);return r;
Greg Kroah-Hartman
maintainerPATCH 428/480 KVM: x86: Add dedicated API for getting mask of accelerated x2APIC MSRs
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sean Christopherson <[email protected]>
commit 8ba621f335a519b47cb7d3e3f4f15b5101b3a56f upstream.
Add a dedicated local APIC API, kvm_x2apic_disable_intercept_reg_mask(), to provide the mask of x2APIC registers whose MSRs can and should be passed through to the guest when x2APIC virtualization is enable, and use it in lieu of the open-coded equivalent VMX logic. Providing a common helper will allow sharing the logic with SVM (x2AVIC), and as a bonus eliminates the somewhat confusing code where KVM enables interception for MSR_TYPE_RW, even though only the READ case actually needs to be updated.
No functional change intended.
--- arch/x86/kvm/lapic.c | 21 +++++++++++++++++++-- arch/x86/kvm/lapic.h | 2 +- arch/x86/kvm/vmx/vmx.c | 3 +-- 3 files changed, 21 insertions(+), 5 deletions(-)
arch/x86/kvm/lapic.c +19 -2
@@ -1745,7 +1745,7 @@ static inline struct kvm_lapic *to_lapic#define APIC_REGS_MASK (first, count) \ (APIC_REG_MASK(first) * ((1ull << (count)) - 1)) -u64 kvm_lapic_readable_reg_mask (struct kvm_lapic *apic) +static u64 kvm_lapic_readable_reg_mask (struct kvm_lapic *apic) {/* Leave bits '0' for reserved and write-only registers. */ u64 valid_reg_mask =
@@ -1781,7 +1781,24 @@ u64 kvm_lapic_readable_reg_mask(struct kreturn valid_reg_mask; } -EXPORT_SYMBOL_FOR_KVM_INTERNAL (kvm_lapic_readable_reg_mask); + +u64 kvm_x2apic_disable_read_intercept_reg_mask (struct kvm_vcpu *vcpu) +{ +if (WARN_ON_ONCE (!lapic_in_kernel (vcpu))) +return 0 ; + +/* +* TMMCT, a.k.a. the current APIC timer count, reads aren't accelerated +* by hardware (Intel or AMD) as the timer is emulated in software (by +* KVM), i.e. reads from the virtual APIC page would return garbage. +* Intercept RDMSR, as handling the fault-like APIC-access VM-Exit is +* more expensive than handling a RDMSR VM-Exit (the APIC-access exit +* requires slow emulation of the code stream). +*/ +return kvm_lapic_readable_reg_mask (vcpu->arch.apic) & + ~APIC_REG_MASK (APIC_TMCCT ); +} +EXPORT_SYMBOL_FOR_KVM_INTERNAL (kvm_x2apic_disable_read_intercept_reg_mask);static int kvm_lapic_reg_read (struct kvm_lapic *apic,u32 offset,int len,void *data)
arch/x86/kvm/lapic.h +1 -1
@@ -150,7 +150,7 @@ int kvm_hv_vapic_msr_read(struct kvm_vcpint kvm_lapic_set_pv_eoi (struct kvm_vcpu *vcpu,u64 data,unsigned long len);void kvm_lapic_exit (void ); -u64 kvm_lapic_readable_reg_mask (struct kvm_lapic *apic); +u64 kvm_x2apic_disable_read_intercept_reg_mask (struct kvm_vcpu *vcpu);static inline void kvm_lapic_set_irr (int vec,struct kvm_lapic *apic) {
arch/x86/kvm/vmx/vmx.c +1 -2
@@ -4080,7 +4080,7 @@ static void vmx_update_msr_bitmap_x2apic* mode, only the current timer count needs on-demand emulation by KVM. */ if (mode &MSR_BITMAP_MODE_X2APIC_APICV ) - msr_bitmap[read_idx] = ~kvm_lapic_readable_reg_mask (vcpu->arch.apic); + msr_bitmap[read_idx] = ~kvm_x2apic_disable_read_intercept_reg_mask (vcpu);else msr_bitmap[read_idx] = ~0ull ; msr_bitmap[write_idx] = ~0ull ;
@@ -4093,7 +4093,6 @@ static void vmx_update_msr_bitmap_x2apic !(mode & MSR_BITMAP_MODE_X2APIC));if (mode &MSR_BITMAP_MODE_X2APIC_APICV ) { -vmx_enable_intercept_for_msr (vcpu,X2APIC_MSR (APIC_TMCCT ),MSR_TYPE_RW );vmx_disable_intercept_for_msr (vcpu,X2APIC_MSR (APIC_EOI ),MSR_TYPE_W );vmx_disable_intercept_for_msr (vcpu,X2APIC_MSR (APIC_SELF_IPI ),MSR_TYPE_W );if (enable_ipiv)
Greg Kroah-Hartman
maintainerPATCH 429/480 KVM: arm64: Dont leak PFN when kvm_translate_vncr() races MMU notifier
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Oliver Upton <[email protected]>
commit 9f76b039a72d7e06374aa96862f0232ed53f7787 upstream.
In the case that kvm_translate_vncr() races with an MMU notifier the early return does not release a reference on the faulted in PFN. Add the necessary call to kvm_release_faultin_page() for the unused PFN.
--- arch/arm64/kvm/nested.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
arch/arm64/kvm/nested.c +3 -1
@@ -1238,8 +1238,10 @@ static int kvm_translate_vncr(struct kvm } scoped_guard(write_lock, &vcpu->kvm->mmu_lock) { -if (mmu_invalidate_retry (vcpu->kvm, mmu_seq)) +if (mmu_invalidate_retry (vcpu->kvm, mmu_seq)) { +kvm_release_faultin_page (vcpu->kvm, page, true, false);return -EAGAIN ; + } vt->gva = va; vt->hpa = pfn <<PAGE_SHIFT ;
Greg Kroah-Hartman
maintainerPATCH 430/480 udmabuf: fix DMA direction mismatch in release_udmabuf()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <[email protected]>
commit fb7b1a0ab25a6077d26cb3829e31743972d4f31d upstream.
begin_cpu_udmabuf() maps the sg_table with the caller-provided direction (e.g., DMA_TO_DEVICE for a write-only sync), and caches it in ubuf->sg for reuse. However, release_udmabuf() always unmaps this sg_table with a hardcoded DMA_BIDIRECTIONAL, regardless of the direction that was originally used for the mapping.
With CONFIG_DMA_API_DEBUG=y this produces:
DMA-API: misc udmabuf: device driver frees DMA memory with different direction [device address=0x000000044a123000] [size=4096 bytes] [mapped with DMA_TO_DEVICE] [unmapped with DMA_BIDIRECTIONAL]
The issue was found during video playback when GStreamer performed a write-only DMA_BUF_IOCTL_SYNC on a udmabuf. It can be reproduced with CONFIG_DMA_API_DEBUG=y by creating a udmabuf from a memfd, performing a write-only sync (DMA_BUF_SYNC_WRITE without DMA_BUF_SYNC_READ), and closing the file descriptor.
Fix this by storing the DMA direction used when the sg_table is first created in begin_cpu_udmabuf(), and passing that same direction to put_sg_table() in release_udmabuf().
--- drivers/dma-buf/udmabuf.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-)
drivers/dma-buf/udmabuf.c +4 -1
@@ -40,6 +40,7 @@ struct udmabuf {struct folio **pinned_folios;struct sg_table *sg; +enum dma_data_direction sg_dir;struct miscdevice *device;pgoff_t *offsets; };
@@ -237,7 +238,7 @@ static void release_udmabuf(struct dma_bstruct device *dev = ubuf->device->this_device;if (ubuf->sg) -put_sg_table (dev, ubuf->sg,DMA_BIDIRECTIONAL ); +put_sg_table (dev, ubuf->sg, ubuf->sg_dir);deinit_udmabuf (ubuf);kfree (ubuf);
@@ -255,6 +256,8 @@ static int begin_cpu_udmabuf(struct dma_if (IS_ERR (ubuf->sg)) { ret =PTR_ERR (ubuf->sg); ubuf->sg =NULL ; + }else { + ubuf->sg_dir = direction; } }else {dma_sync_sgtable_for_cpu (dev, ubuf->sg, direction);
Greg Kroah-Hartman
maintainerPATCH 431/480 dma-buf/udmabuf: skip redundant cpu sync to fix cacheline EEXIST warning
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <[email protected]>
commit 504e2b4ab97a51d56d966cd36d0997ad30b65b2d upstream.
When CONFIG_DMA_API_DEBUG_SG is enabled, importing a udmabuf into a DRM driver (e.g. amdgpu for video playback in GNOME Videos / Showtime) triggers a spurious warning:
DMA-API: amdgpu 0000:03:00.0: cacheline tracking EEXIST, \
overlapping mappings aren't supported
WARNING: kernel/dma/debug.c:619 at add_dma_entry+0x473/0x5f0The call chain is:
amdgpu_cs_ioctl
-> amdgpu_ttm_backend_bind
-> dma_buf_map_attachment
-> [udmabuf] map_udmabuf -> get_sg_table
-> dma_map_sgtable(dev, sg, direction, 0) // attrs=0
-> debug_dma_map_sg -> add_dma_entry -> EEXISTThis happens because udmabuf builds a per-page scatter-gather list via sg_set_folio(). When begin_cpu_udmabuf() has already created an sg table mapped for the misc device, and an importer such as amdgpu maps the same pages for its own device via map_udmabuf(), the DMA debug infrastructure sees two active mappings whose physical addresses share cacheline boundaries and warns about the overlap.
The DMA_ATTR_SKIP_CPU_SYNC flag suppresses this check in add_dma_entry() because it signals that no CPU cache maintenance is performed at map/unmap time, making the cacheline overlap harmless.
All other major dma-buf exporters already pass this flag:
- drm_gem_map_dma_buf() passes DMA_ATTR_SKIP_CPU_SYNC
- amdgpu_dma_buf_map() passes DMA_ATTR_SKIP_CPU_SYNC
The CPU sync at map/unmap time is also redundant for udmabuf:begin_cpu_udmabuf() and end_cpu_udmabuf() already perform explicit cache synchronization via dma_sync_sgtable_for_cpu/device() when CPU access is requested through the dma-buf interface.
Pass DMA_ATTR_SKIP_CPU_SYNC to dma_map_sgtable() and dma_unmap_sgtable() in udmabuf to suppress the spurious warning and skip the redundant sync.
--- drivers/dma-buf/udmabuf.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/dma-buf/udmabuf.c +2 -2
@@ -163,7 +163,7 @@ static struct sg_table *get_sg_table(strsg_set_folio (sgl, ubuf->folios[i],PAGE_SIZE , ubuf->offsets[i]); - ret =dma_map_sgtable (dev, sg, direction,0 ); + ret =dma_map_sgtable (dev, sg, direction,DMA_ATTR_SKIP_CPU_SYNC );if (ret <0 ) goto err_map;return sg;
@@ -178,7 +178,7 @@ err_alloc:static void put_sg_table (struct device *dev,struct sg_table *sg,enum dma_data_direction direction) { -dma_unmap_sgtable (dev, sg, direction,0 ); +dma_unmap_sgtable (dev, sg, direction,DMA_ATTR_SKIP_CPU_SYNC );sg_free_table (sg);kfree (sg); }
Greg Kroah-Hartman
maintainerPATCH 432/480 fpga: dfl-afu: validate DMA mapping length in afu_dma_map_region()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Sebastian Alba Vives <[email protected]>
commit fc3b071a7c8dc0f5d56defddf6e6fd5aaa3e1e27 upstream.
afu_ioctl_dma_map() accepts a 64-bit length from userspace via DFL_FPGA_PORT_DMA_MAP ioctl without an upper bound check. The value is passed to afu_dma_pin_pages() where npages is derived as length >> PAGE_SHIFT and passed to pin_user_pages_fast() which takes int nr_pages, causing implicit truncation if length is very large.
Validate map.length at the ioctl entry point before calling afu_dma_map_region(), rejecting values whose page count exceeds INT_MAX.
--- drivers/fpga/dfl-afu-main.c | 3 +++ 1 file changed, 3 insertions(+)
drivers/fpga/dfl-afu-main.c +3 -0
@@ -723,6 +723,9 @@ afu_ioctl_dma_map(struct dfl_feature_devif (map.argsz < minsz || map.flags)return -EINVAL ; +if (map.length >>PAGE_SHIFT > (u64 )INT_MAX ) +return -EINVAL ; + ret =afu_dma_map_region (fdata, map.user_addr, map.length, &map.iova);if (ret)return ret;
Greg Kroah-Hartman
maintainerPATCH 433/480 i2c: core: fix adapter probe deferral loop
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 158efa411c57111d87bf265a3776614f32d70007 upstream.
Drivers must not probe defer after having registered devices as that will trigger a probe loop if the devices bind to a driver (cf. commit fbc35b45f9f6 ("Add documentation on meaning of -EPROBE_DEFER")).
Move the recovery initialisation, where the GPIO lookup may fail, before registering the adapter to prevent this.
--- drivers/i2c/i2c-core-base.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/i2c/i2c-core-base.c +4 -4
@@ -1562,6 +1562,10 @@ static int i2c_register_adapter(struct i adap->dev.type = &i2c_adapter_type;device_initialize (&adap->dev); + res =i2c_init_recovery (adap); +if (res == -EPROBE_DEFER ) + goto err_put_adap; +/* * This adapter can be used as a parent immediately after device_add(), * setup runtime-pm (especially ignore-children) before hand.
@@ -1588,10 +1592,6 @@ static int i2c_register_adapter(struct iif (res) goto out_reg; - res =i2c_init_recovery (adap); -if (res == -EPROBE_DEFER ) - goto out_reg; -dev_dbg (&adap->dev,"adapter [%s] registered\n" , adap->name);/* create pre-declared device nodes */
Greg Kroah-Hartman
maintainerPATCH 434/480 i2c: core: fix irq domain leak on adapter registration failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 8ce19524e4cc2462685f596a6402fbd8fb984ab2 upstream.
Make sure to tear down the host notify irq domain on adapter registration failure to avoid leaking it.
This issue was flagged by Sashiko when reviewing another adapter registration fix.
--- drivers/i2c/i2c-core-base.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/i2c/i2c-core-base.c +3 -1
@@ -1583,7 +1583,7 @@ static int i2c_register_adapter(struct iif (res) {pr_err ("adapter '%s': can't register device (%d)\n" , adap->name, res);put_device (&adap->dev); - goto out_list; + goto err_remove_irq_domain; } adap->debugfs =debugfs_create_dir (dev_name (&adap->dev), i2c_debugfs_root);
@@ -1615,6 +1615,8 @@ out_reg:init_completion (&adap->dev_released);device_unregister (&adap->dev);wait_for_completion (&adap->dev_released); +err_remove_irq_domain: +i2c_host_notify_irq_teardown (adap); out_list:mutex_lock (&core_lock);idr_remove (&i2c_adapter_idr, adap->nr);
Greg Kroah-Hartman
maintainerPATCH 435/480 i2c: core: fix NULL-deref on adapter registration failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 2295d2bb101faa663fbc45fadbb3fec45f107441 upstream.
If adapter registration ever fails the release callback would trigger a NULL-pointer dereference as the completion struct has not been initialised.
Note that before the offending commit this would instead have resulted in a minor memory leak of the adapter name.
--- drivers/i2c/i2c-core-base.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-)
drivers/i2c/i2c-core-base.c +5 -4
@@ -1582,8 +1582,7 @@ static int i2c_register_adapter(struct i res =device_add (&adap->dev);if (res) {pr_err ("adapter '%s': can't register device (%d)\n" , adap->name, res); -put_device (&adap->dev); - goto err_remove_irq_domain; + goto err_put_adap; } adap->debugfs =debugfs_create_dir (dev_name (&adap->dev), i2c_debugfs_root);
@@ -1612,10 +1611,12 @@ static int i2c_register_adapter(struct i out_reg:i2c_deregister_clients (adap);debugfs_remove_recursive (adap->debugfs); +device_del (&adap->dev); +err_put_adap:init_completion (&adap->dev_released); -device_unregister (&adap->dev); +put_device (&adap->dev);wait_for_completion (&adap->dev_released); -err_remove_irq_domain: +i2c_host_notify_irq_teardown (adap); out_list:mutex_lock (&core_lock);
Greg Kroah-Hartman
maintainerPATCH 436/480 i2c: core: fix adapter debugfs creation
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit 07d5fb537928aad4369aaff0cbae73ba38a719af upstream.
Clients can be registered from bus notifier callbacks so the debugfs directory needs to be created before registering the adapter as clients use that directory as their debugfs parent.
Move debugfs creation before adapter registration to avoid having clients create their debugfs directories in the debugfs root (which is also more likely to fail due to name collisions).
Note that failure to allocate the adapter name must now be handled explicitly as debugfs_create_dir() cannot handle a NULL name (unlike device_add() which returns an error).
--- drivers/i2c/i2c-core-base.c | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-)
drivers/i2c/i2c-core-base.c +10 -6
@@ -1557,7 +1557,10 @@ static int i2c_register_adapter(struct i goto out_list; } -dev_set_name (&adap->dev,"i2c-%d" , adap->nr); + res =dev_set_name (&adap->dev,"i2c-%d" , adap->nr); +if (res) + goto err_remove_irq_domain; + adap->dev.bus = &i2c_bus_type; adap->dev.type = &i2c_adapter_type;device_initialize (&adap->dev);
@@ -1579,14 +1582,14 @@ static int i2c_register_adapter(struct iidr_replace (&i2c_adapter_idr, adap, adap->nr);mutex_unlock (&core_lock); + adap->debugfs =debugfs_create_dir (dev_name (&adap->dev), i2c_debugfs_root); + res =device_add (&adap->dev);if (res) {pr_err ("adapter '%s': can't register device (%d)\n" , adap->name, res); - goto err_put_adap; + goto err_remove_debugfs; } - adap->debugfs =debugfs_create_dir (dev_name (&adap->dev), i2c_debugfs_root); - res =i2c_setup_smbus_alert (adap);if (res) goto out_reg;
@@ -1610,13 +1613,14 @@ static int i2c_register_adapter(struct i out_reg:i2c_deregister_clients (adap); -debugfs_remove_recursive (adap->debugfs);device_del (&adap->dev); +err_remove_debugfs: +debugfs_remove_recursive (adap->debugfs); err_put_adap:init_completion (&adap->dev_released);put_device (&adap->dev);wait_for_completion (&adap->dev_released); - +err_remove_irq_domain:i2c_host_notify_irq_teardown (adap); out_list:mutex_lock (&core_lock);
Greg Kroah-Hartman
maintainerPATCH 437/480 i2c: core: fix adapter deregistration race
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Johan Hovold <[email protected]>
commit b1a58ed9eab146b36f41a55db8f5d7ce9fdedf3f upstream.
Adapters can be looked up by their id using i2c_get_adapter() which takes a reference to the embedded struct device.
Remove the adapter from the IDR before tearing it down during deregistration (and on registration failure) to make sure its resources are not accessed after having been freed (e.g. the device name).
--- drivers/i2c/i2c-core-base.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/i2c/i2c-core-base.c +7 -2
@@ -1587,7 +1587,7 @@ static int i2c_register_adapter(struct i res =device_add (&adap->dev);if (res) {pr_err ("adapter '%s': can't register device (%d)\n" , adap->name, res); - goto err_remove_debugfs; + goto err_replace_id; } res =i2c_setup_smbus_alert (adap);
@@ -1614,7 +1614,10 @@ static int i2c_register_adapter(struct i out_reg:i2c_deregister_clients (adap);device_del (&adap->dev); -err_remove_debugfs: +err_replace_id: +mutex_lock (&core_lock); +idr_replace (&i2c_adapter_idr,NULL , adap->nr); +mutex_unlock (&core_lock);debugfs_remove_recursive (adap->debugfs); err_put_adap:init_completion (&adap->dev_released);
@@ -1803,6 +1806,8 @@ void i2c_del_adapter(struct i2c_adapter/* First make sure that this adapter was ever added */ mutex_lock (&core_lock); found =idr_find (&i2c_adapter_idr, adap->nr); +if (found == adap) +idr_replace (&i2c_adapter_idr,NULL , adap->nr);mutex_unlock (&core_lock);if (found != adap) {pr_debug ("attempting to delete unregistered adapter [%s]\n" , adap->name);
Greg Kroah-Hartman
maintainerPATCH 438/480 i2c: mpc: Fix timeout calculations
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Andy Shevchenko <[email protected]>
commit 2e9a7f68329be41792c0b123c28e6c53c2fa2249 upstream.
At first glance the harmless cleanup of the driver does nothing bad. However, as the operator precedence list states the '*' (multiplication) and '/' division operators have order 5 with left-to-right associativity the *= has order 17 and associativity right-to-left. It wouldn't be a problem to replace
foo = foo * HZ / 1000000;
with
foo *= HZ / 1000000;
if HZ constant is in Hertz. The problem is that in the Linux kernel HZ is defined in jiffy units, which is order of magnitude smaller than a million. That's why operator precedence has a crucial role here. Fix the regression by reverting pre-optimized calculations.
--- drivers/i2c/busses/i2c-mpc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-mpc.c +1 -1
@@ -844,7 +844,7 @@ static int fsl_i2c_probe(struct platform "fsl,timeout", &mpc_ops.timeout);if (!result) { - mpc_ops.timeout *=HZ /1000000 ; + mpc_ops.timeout = mpc_ops.timeout *HZ /1000000 ;if (mpc_ops.timeout <5 ) mpc_ops.timeout =5 ; }else {
Greg Kroah-Hartman
maintainerPATCH 439/480 i2c: davinci: Unregister cpufreq notifier on probe failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit e43f32816a1b1fe5a86279411626fe3a9be56d45 upstream.
davinci_i2c_probe() registers a cpufreq transition notifier before adding the I2C adapter. If i2c_add_numbered_adapter() fails, the probe error path releases the device resources without unregistering the notifier.
Add a dedicated error path to unregister the cpufreq notifier after i2c_add_numbered_adapter() fails.
--- drivers/i2c/busses/i2c-davinci.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-davinci.c +3 -1
@@ -818,12 +818,14 @@ static int davinci_i2c_probe(struct plat adap->nr = pdev->id; r =i2c_add_numbered_adapter (adap);if (r) - goto err_unuse_clocks; + goto err_cpufreq;pm_runtime_put_autosuspend (dev->dev);return 0 ; +err_cpufreq: +i2c_davinci_cpufreq_deregister (dev); err_unuse_clocks:pm_runtime_dont_use_autosuspend (dev->dev);pm_runtime_put_sync (dev->dev);
Greg Kroah-Hartman
maintainerPATCH 440/480 i2c: stm32f7: truncate clock period instead of rounding it
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Guillermo Rodríguez <[email protected]>
commit 111bb7f9f4a90b32e495d70a607c67b137f3074a upstream.
stm32f7_i2c_compute_timing() derives the I2C clock source period (i2cclk) with DIV_ROUND_CLOSEST, which may round it up. When the period is overestimated, all timings computed from it (SCLDEL, SDADEL, SCLL, SCLH) come out shorter on the wire than calculated, and the resulting bus rate can exceed the requested speed, violating the I2C specification minimums for tLOW and tHIGH.
For example, with a 104.45 MHz clock source (e.g. PCLK1, the reset-default I2C clock source on STM32MP1), i2cclk is rounded from 9.574 ns up to 10 ns. Requesting a 400 kHz fast mode bus with 72/27 ns rise/fall times and no analog/digital filters then produces an actual bus rate of 415.6 kHz with tLOW = 1254 ns, violating both the 400 kHz maximum rate and the 1300 ns tLOW minimum of the specification.
Truncate the period instead, so that it can only be underestimated. The error then falls on the safe side: the programmed timings come out slightly longer than computed and the bus runs marginally below the target rate (375.3 kHz in the example above) while meeting the specification.
i2cbus is left rounded-to-closest: it is only used as the target of the clk_error comparison and is never multiplied into the programmed timings, so nearest rounding remains accurate there.
--- drivers/i2c/busses/i2c-stm32f7.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
drivers/i2c/busses/i2c-stm32f7.c +7 -2
@@ -464,8 +464,13 @@ static int stm32f7_i2c_compute_timing(st {struct stm32f7_i2c_spec *specs;u32 p_prev =STM32F7_PRESC_MAX ; -u32 i2cclk =DIV_ROUND_CLOSEST (NSEC_PER_SEC , - setup->clock_src); +/* +* Truncate instead of rounding to closest: if the clock period is +* overestimated, the computed SCL timings will come out shorter on +* the wire, which can push the bus above the target rate and below +* the spec's tLOW/tHIGH minimums. +*/ +u32 i2cclk =NSEC_PER_SEC / setup->clock_src;u32 i2cbus =DIV_ROUND_CLOSEST (NSEC_PER_SEC , setup->speed_freq);u32 clk_error_prev = i2cbus;
Greg Kroah-Hartman
maintainerPATCH 441/480 i2c: imx-lpi2c: mark I2C adapter when hardware is powered down
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Carlos Song <[email protected]>
commit 218cfe364b55b2768221629bd4a69ad190b7fbbc upstream.
On some i.MX platforms, certain I2C client drivers keep a periodic workqueue which continues to trigger I2C transfers.
During system suspend/resume, there exists a time window between:
- suspend_noirq and the system entering suspend
- the system starting to resume and resume_noirq
In this window, the I2C controller resources such as clock and pinctrl may already be disabled or not yet restored.
If a workqueue triggers an I2C transfer in this period, the driver attempts to access I2C registers while the hardware resources are unavailable, which may lead to system hang.
Mark the I2C adapter as suspended during noirq suspend and block new transfers until resume, ensuring that I2C transfers are only issued when hardware resources are available.
--- drivers/i2c/busses/i2c-imx-lpi2c.c | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-)
drivers/i2c/busses/i2c-imx-lpi2c.c +14 -1
@@ -1588,7 +1588,18 @@ static int __maybe_unused lpi2c_runtime_static int __maybe_unused lpi2c_suspend_noirq (struct device *dev) { -return pm_runtime_force_suspend (dev); +struct lpi2c_imx_struct *lpi2c_imx =dev_get_drvdata (dev); +int ret; + +i2c_mark_adapter_suspended (&lpi2c_imx->adapter); + + ret =pm_runtime_force_suspend (dev); +if (ret) { +i2c_mark_adapter_resumed (&lpi2c_imx->adapter); +return ret; + } + +return 0 ; }static int __maybe_unused lpi2c_resume_noirq (struct device *dev)
@@ -1608,6 +1619,8 @@ static int __maybe_unused lpi2c_resume_nif (lpi2c_imx->target)lpi2c_imx_target_init (lpi2c_imx); +i2c_mark_adapter_resumed (&lpi2c_imx->adapter); +return 0 ; }
Greg Kroah-Hartman
maintainerPATCH 442/480 i2c: i801: fix hardware state machine corruption in error path
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mingyu Wang <[email protected]>
commit 10dd1a736d557e310a77117832874729a0175d57 upstream.
A severe livelock and subsequent Hung Task panic were observed in the i2c-i801 driver during concurrent Fuzzing. The crash is caused by an unconditional hardware register cleanup in the error handling path of i801_access().
When i801_check_pre() fails (e.g., returning -EBUSY because the SMBus controller is actively used by BIOS/ACPI), the kernel does not actually acquire the hardware ownership. However, the code jumps to the 'out' label and executes:
iowrite8(SMBHSTSTS_INUSE_STS | STATUS_FLAGS, SMBHSTSTS(priv));
This forcefully clears the INUSE_STS lock and resets the hardware status flags without owning the controller. Doing so interrupts ongoing BIOS/ACPI transactions and totally corrupts the SMBus hardware state machine.
Consequently, all subsequent i801_access() calls fail at the pre-check stage, triggering an endless stream of "SMBus is busy, can't use it!" error logs. Over a slow serial console, this printk flood monopolizes the CPU (Console Livelock), starving other processes trying to acquire the mmap_lock down_read semaphore, ultimately triggering the hung task watchdog.
Fix this by moving the 'out' label below the hardware register cleanup. If i801_check_pre() fails, we safely bypass the iowrite8() and only release the software locks (pm_runtime and mutex), strictly adhering to the rule of not releasing resources that were never acquired.
--- drivers/i2c/busses/i2c-i801.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/i2c/busses/i2c-i801.c +1 -1
@@ -927,13 +927,13 @@ static s32 i801_access(struct i2c_adapte*/ if (hwpec)iowrite8 (ioread8 (SMBAUXCTL (priv)) & ~SMBAUXCTL_CRC ,SMBAUXCTL (priv)); -out:/* * Unlock the SMBus device for use by BIOS/ACPI, * and clear status flags if not done already. */ iowrite8 (SMBHSTSTS_INUSE_STS |STATUS_FLAGS ,SMBHSTSTS (priv)); +out:pm_runtime_put_autosuspend (&priv->pci_dev->dev);mutex_unlock (&priv->acpi_lock);return ret;
Greg Kroah-Hartman
maintainerPATCH 443/480 Input: synaptics-rmi4 - unregister function handlers on physical driver registration failure
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Haoxiang Li <[email protected]>
commit 6251f7d3472c0409e30f8d6a24f10d33d12e3f9a upstream.
If rmi_register_physical_driver() fails, the current error path unregisters only the RMI bus. The function handlers registered earlier remain registered with the driver core.
Add a separate error path to unregister the function handlers before unregistering the bus in this failure case.
--- drivers/input/rmi4/rmi_bus.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/input/rmi4/rmi_bus.c +3 -1
@@ -455,11 +455,13 @@ static int __init rmi_bus_init(void)if (error) {pr_err ("%s: error registering the RMI physical driver: %d\n" , __func__, error); - goto err_unregister_bus; + goto err_unregister_function_handlers; }return 0 ; +err_unregister_function_handlers: +rmi_unregister_function_handlers (); err_unregister_bus:bus_unregister (&rmi_bus_type);return error;
Greg Kroah-Hartman
maintainerPATCH 444/480 Input: synaptics-rmi4 - bound the F3A keymap to the GPIO count
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 57c10915f2c16c90e0d46ad00876bf39ece40fc2 upstream.
rmi_f3a_initialize() takes the GPIO count from the device query register (f3a->gpio_count = buf & RMI_F3A_GPIO_COUNT, range 0..127). rmi_f3a_map_gpios() then allocates gpio_key_map with min(gpio_count, TRACKSTICK_RANGE_END) == at most 6 entries, but rmi_f3a_attention() iterates the full gpio_count and dereferences gpio_key_map[i], and input->keycodemax is set to the full gpio_count while input->keycode points at the 6-entry allocation.
A device that reports gpio_count > 6 therefore causes an out-of-bounds read of gpio_key_map[] on every attention interrupt, and out-of-bounds accesses through the input core's default keymap ioctls: EVIOCGKEYCODE reads past the buffer (leaking adjacent slab memory to user space) and EVIOCSKEYCODE writes a caller-controlled value past it, for any process able to open the evdev node, since input_default_getkeycode() and input_default_setkeycode() only bound the index against keycodemax.
Size the keymap for the full gpio_count. The mapping loop is unchanged:
it still assigns only the first min(gpio_count, TRACKSTICK_RANGE_END) entries; the remaining slots stay KEY_RESERVED (devm_kcalloc zero-fills) and are skipped when reporting.
--- drivers/input/rmi4/rmi_f3a.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/rmi4/rmi_f3a.c +1 -1
@@ -132,7 +132,7 @@ static int rmi_f3a_map_gpios(struct rmi_int button_count =min_t (u8, f3a->gpio_count,TRACKSTICK_RANGE_END ); f3a->gpio_key_map =devm_kcalloc (&fn->dev, - button_count, + f3a->gpio_count,sizeof (f3a->gpio_key_map[0 ]),GFP_KERNEL );if (!f3a->gpio_key_map) {
Greg Kroah-Hartman
maintainerPATCH 445/480 Input: synaptics-rmi4 - bound the F30 keymap to the GPIO/LED count
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit d577e46785d45484b2ab7e7309c49b18764bf56c upstream.
rmi_f30_map_gpios() allocates gpioled_key_map with min(gpioled_count, TRACKSTICK_RANGE_END) == at most 6 entries, but rmi_f30_attention() iterates the full f30->gpioled_count (device query register, range 0..31) and dereferences gpioled_key_map[i], and input->keycodemax is set to the full gpioled_count while input->keycode points at the 6-entry allocation.
A device that reports gpioled_count > 6 with GPIO support enabled therefore causes an out-of-bounds read on the attention interrupt and out-of-bounds read/write through the EVIOCGKEYCODE/EVIOCSKEYCODE ioctls, which bound the index only against keycodemax. This is the same defect as the F3A handler, which was copied from F30.
Size the keymap for the full gpioled_count; the mapping loop still assigns only the first min(gpioled_count, TRACKSTICK_RANGE_END) entries.
--- drivers/input/rmi4/rmi_f30.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/rmi4/rmi_f30.c +1 -1
@@ -233,7 +233,7 @@ static int rmi_f30_map_gpios(struct rmi_int button_count =min_t (u8, f30->gpioled_count,TRACKSTICK_RANGE_END ); f30->gpioled_key_map =devm_kcalloc (&fn->dev, - button_count, + f30->gpioled_count,sizeof (f30->gpioled_key_map[0 ]),GFP_KERNEL );if (!f30->gpioled_key_map) {
Greg Kroah-Hartman
maintainerPATCH 446/480 Input: elan_i2c - prevent division by zero and arithmetic underflow
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ranjan Kumar <[email protected]>
commit df2b818fa009c10ff6ba875a1663ff001cda9558 upstream.
The Elan I2C touchpad driver queries the device for its physical dimensions and trace counts to calculate the device resolution and width. However, if the device firmware or device tree provides invalid zero values for x_traces or y_traces, it results in a fatal division-by-zero exception leading to a kernel panic during device probe.
Add checks to ensure these parameters are non-zero before performing the division. If invalid trace values are detected, fall back to a safe default of 1.
Additionally, prevent an arithmetic underflow in the touch reporting logic. Previously, if the calculated or fallback width was smaller than ETP_FWIDTH_REDUCE (90), the subtraction would underflow, resulting in a massive unsigned integer being reported to userspace. Clamp the adjusted width to a minimum of 0 to safely handle small physical dimensions and fallback scenarios.
Completing the probe with safe fallback values ensures the sysfs nodes are created, keeping the firmware update path intact so a recovery firmware can be flashed to the device.
--- drivers/input/mouse/elan_i2c_core.c | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-)
drivers/input/mouse/elan_i2c_core.c +30 -6
@@ -425,8 +425,17 @@ static int elan_query_device_parameters(if (error)return error; } - data->width_x = data->max_x / x_traces; - data->width_y = data->max_y / y_traces; + +if (!x_traces || !y_traces) { +dev_warn (&client->dev, +"invalid trace numbers: x=%u, y=%u\n" , + x_traces, y_traces); + data->width_x =1 ; + data->width_y =1 ; + }else { + data->width_x = data->max_x / x_traces; + data->width_y = data->max_y / y_traces; + } if (device_property_read_u32(&client->dev, "touchscreen-x-mm", &x_mm) ||
@@ -440,8 +449,16 @@ static int elan_query_device_parameters( data->x_res =elan_convert_resolution (hw_x_res, data->pattern); data->y_res =elan_convert_resolution (hw_y_res, data->pattern); }else { - data->x_res = (data->max_x +1 ) / x_mm; - data->y_res = (data->max_y +1 ) / y_mm; +if (unlikely (x_mm ==0 || y_mm ==0 )) { +dev_warn (&client->dev, +"invalid physical dimensions: x_mm=%u, y_mm=%u\n" , + x_mm, y_mm); + data->x_res =1 ; + data->y_res =1 ; + }else { + data->x_res = (data->max_x +1 ) / x_mm; + data->y_res = (data->max_y +1 ) / y_mm; + } }if (device_property_read_bool (&client->dev,"elan,clickpad" ))
@@ -953,6 +970,7 @@ static void elan_report_contact(struct eif (data->report_features &ETP_FEATURE_REPORT_MK ) {unsigned int mk_x, mk_y, area_x, area_y; +int adj_width_x, adj_width_y;u8 mk_data = high_precision ? packet[ETP_MK_DATA_OFFSET + contact_num] : finger_data[3 ];
@@ -964,8 +982,14 @@ static void elan_report_contact(struct e* To avoid treating large finger as palm, let's reduce * the width x and y per trace. */ - area_x = mk_x * (data->width_x -ETP_FWIDTH_REDUCE ); - area_y = mk_y * (data->width_y -ETP_FWIDTH_REDUCE ); + + adj_width_x = data->width_x >ETP_FWIDTH_REDUCE ? + data->width_x -ETP_FWIDTH_REDUCE :0 ; + adj_width_y = data->width_y >ETP_FWIDTH_REDUCE ? + data->width_y -ETP_FWIDTH_REDUCE :0 ; + + area_x = mk_x * adj_width_x; + area_y = mk_y * adj_width_y;input_report_abs (input,ABS_TOOL_WIDTH , mk_x); input_report_abs(input, ABS_MT_TOUCH_MAJOR,
Greg Kroah-Hartman
maintainerPATCH 447/480 Input: goodix - clamp the device-reported contact count
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 5ed62a96e06be4e94b8296b7932afee550a70e04 upstream.
goodix_ts_read_input_report() copies the number of touch points reported by the device into an on-stack buffer
u8 point_data[2 + GOODIX_MAX_CONTACT_SIZE * GOODIX_MAX_CONTACTS];
which is sized for at most GOODIX_MAX_CONTACTS (10) contacts. The only runtime check bounds the per-interrupt count against ts->max_touch_num, but that value is taken verbatim from a 4-bit field of the device configuration block and is never clamped:
ts->max_touch_num = ts->config[MAX_CONTACTS_LOC] & 0x0f;
The nibble can be 0..15, so a malfunctioning, malicious or counterfeit controller (or an attacker tampering with the I2C bus) can advertise up to 15 contacts. goodix_ts_read_input_report() then accepts a touch_num of up to 15 and the second goodix_i2c_read() writes ts->contact_size * (touch_num - 1) bytes past the one-contact header into point_data - up to 30 bytes (45 with the 9-byte report format) beyond the 92-byte buffer: a stack out-of-bounds write.
Clamp max_touch_num to GOODIX_MAX_CONTACTS, the number of contacts point_data[] is sized for, when reading it from the configuration.
--- drivers/input/touchscreen/goodix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/input/touchscreen/goodix.c +2 -1
@@ -1057,7 +1057,8 @@ static void goodix_read_config(struct go } ts->int_trigger_type = ts->config[TRIGGER_LOC ] &0x03 ; - ts->max_touch_num = ts->config[MAX_CONTACTS_LOC ] &0x0f ; + ts->max_touch_num =min (ts->config[MAX_CONTACTS_LOC ] &0x0f , +GOODIX_MAX_CONTACTS ); x_max =get_unaligned_le16 (&ts->config[RESOLUTION_LOC ]); y_max =get_unaligned_le16 (&ts->config[RESOLUTION_LOC +2 ]);
Greg Kroah-Hartman
maintainerPATCH 448/480 Input: iforce - bound the device-reported force-feedback effect index
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 0e9943d2e4c63496b6ca84bc66fd3c71d40558e2 upstream.
iforce_process_packet() handles a status report (packet id 0x02) by taking a force-feedback effect index straight from the device wire and using it to address the per-effect state array:
i = data[1] & 0x7f;
if (data[1] & 0x80) {
if (!test_and_set_bit(FF_CORE_IS_PLAYED,
iforce->core_effects[i].flags))
...
} else if (test_and_clear_bit(FF_CORE_IS_PLAYED,
iforce->core_effects[i].flags)) {
...
}The index is masked only with 0x7f, so it ranges 0..127, but core_effects[] holds only IFORCE_EFFECTS_MAX (32) entries. For an index of 32..127 the test_and_set_bit()/test_and_clear_bit() is an out-of-bounds single-bit read-modify-write past the array. core_effects[] is the second-to-last member of struct iforce, so the write lands in the trailing members and beyond the embedding kzalloc()'d iforce_serio / iforce_usb object.
data[1] is unvalidated device payload on both transports (the USB interrupt endpoint and serio), and the status path is not gated on force feedback being present, so a malicious or counterfeit device can set or clear a bit at an attacker-chosen offset past the object.
Reject an out-of-range index instead of indexing with it. Bound against the array dimension IFORCE_EFFECTS_MAX rather than dev->ff->max_effects so the check guarantees memory safety regardless of how many effects the device registered. A legitimate "effect started/stopped" status always carries an index below IFORCE_EFFECTS_MAX, so well-formed devices are unaffected; the neighbouring mark_core_as_ready() loop is already bounded and is left untouched.
--- drivers/input/joystick/iforce/iforce-packets.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-)
drivers/input/joystick/iforce/iforce-packets.c +11 -7
@@ -186,14 +186,18 @@ void iforce_process_packet(struct iforce/* Check if an effect was just started or stopped */ i = data[1 ] &0x7f ; -if (data[1 ] &0x80 ) { -if (!test_and_set_bit (FF_CORE_IS_PLAYED , iforce->core_effects[i].flags)) { -/* Report play event */ -input_report_ff_status (dev, i,FF_STATUS_PLAYING ); +if (i <IFORCE_EFFECTS_MAX ) { +if (data[1 ] &0x80 ) { +if (!test_and_set_bit (FF_CORE_IS_PLAYED , + iforce->core_effects[i].flags)) { +/* Report play event */ +input_report_ff_status (dev, i,FF_STATUS_PLAYING ); + } + }else if (test_and_clear_bit (FF_CORE_IS_PLAYED , + iforce->core_effects[i].flags)) { +/* Report stop event */ +input_report_ff_status (dev, i,FF_STATUS_STOPPED ); } - }else if (test_and_clear_bit (FF_CORE_IS_PLAYED , iforce->core_effects[i].flags)) { -/* Report stop event */ -input_report_ff_status (dev, i,FF_STATUS_STOPPED ); }for (j =3 ; j < len; j +=2 )
Greg Kroah-Hartman
maintainerPATCH 449/480 Input: mms114 - fix touch indexing for MMS134S and MMS136
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit a6ac4e24c1a8a533bb61035184fdcc7eede4cc8d upstream.
The MMS134S and MMS136 touch controllers have an event size of 6 bytes rather than 8 bytes. When __mms114_read_reg() reads the touch data packet from the device into the touch buffer, the events are packed tightly at 6-byte intervals. However, the driver iterates through the events using standard C array indexing (touch[index]), where each element is sizeof(struct mms114_touch) (8 bytes) apart. As a result, any touch events beyond the first one are read from incorrect offsets and parsed improperly.
Fix this by explicitly calculating the byte offset for each touch event based on the device's specific event size.
--- drivers/input/touchscreen/mms114.c | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-)
drivers/input/touchscreen/mms114.c +12 -6
@@ -218,7 +218,9 @@ static irqreturn_t mms114_interrupt(intstruct i2c_client *client = data->client;struct input_dev *input_dev = data->input_dev;struct mms114_touch touch[MMS114_MAX_TOUCH ]; +struct mms114_touch *t;int packet_size; +int event_size;int touch_size;int index;int error;
@@ -236,9 +238,11 @@ static irqreturn_t mms114_interrupt(int/* MMS136 has slightly different event size */ if (data->type ==TYPE_MMS134S || data->type ==TYPE_MMS136 ) - touch_size = packet_size /MMS136_EVENT_SIZE ; + event_size =MMS136_EVENT_SIZE ;else - touch_size = packet_size /MMS114_EVENT_SIZE ; + event_size =MMS114_EVENT_SIZE ; + + touch_size = packet_size / event_size; error =__mms114_read_reg (data,MMS114_INFORMATION , packet_size, (u8 *)touch);
@@ -246,18 +250,20 @@ static irqreturn_t mms114_interrupt(int goto out;for (index =0 ; index < touch_size; index++) { -switch (touch[index].type) { + t = (struct mms114_touch *)((u8 *)touch + index * event_size); + +switch (t->type) {case MMS114_TYPE_TOUCHSCREEN : -mms114_process_mt (data, touch + index); +mms114_process_mt (data, t);break ;case MMS114_TYPE_TOUCHKEY : -mms114_process_touchkey (data, touch + index); +mms114_process_touchkey (data, t);break ;default :dev_err (&client->dev,"Wrong touch type (%d)\n" , - touch[index].type); + t->type);break ; } }
Greg Kroah-Hartman
maintainerPATCH 450/480 Input: ads7846 - dont use scratch for tx_buf when clearing register
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Kris Bahnsen <[email protected]>
commit 856668312685d9a8f32d49a135a89c429d309f81 upstream.
The workaround for XPT2046 clears the command register, giving the touchscreen controller a NOP. The change incorrectly re-uses the req->scratch variable which is used as rx_buf for xfer[5], so by the time xfer[6] occurs, the contents of req->scratch may not be
0. It was found that the touchscreen controller can end up in a completely unresponsive state due to it being given a command the driver does not expect.
Instead, rely on the spi_transfer behavior of tx_buf being NULL to transmit all 0 bits and use the scratch variable for the rx_buf for both the 1 byte command to and 2 byte response from the controller.
Also relocates the scratch member of struct ser_req to force it into a different cache line to prevent any potential issues of DMA stepping on unrelated data in other struct members due to sharing the same cache line.
This change was tested on real TSC2046 and ADS7843 controllers, but not the XPT2046 the workaround was originally created for. Confirming that the original modification to clear the command register does not impact either real controller.
--- drivers/input/touchscreen/ads7846.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-)
drivers/input/touchscreen/ads7846.c +2 -3
@@ -329,7 +329,6 @@ struct ser_req {u8 ref_on;u8 command;u8 ref_off; -u16 scratch;struct spi_message msg;struct spi_transfer xfer[8 ];/*
@@ -337,6 +336,7 @@ struct ser_req {* transfer buffers to live in their own cache lines. */ __be16 sample____cacheline_aligned ; +u16 scratch; };struct ads7845_ser_req {
@@ -408,8 +408,7 @@ static int ads7846_read12_ser(struct devspi_message_add_tail (&req->xfer[5 ], &req->msg);/* clear the command register */ - req->scratch =0 ; - req->xfer[6 ].tx_buf = &req->scratch; + req->xfer[6 ].rx_buf = &req->scratch; req->xfer[6 ].len =1 ;spi_message_add_tail (&req->xfer[6 ], &req->msg);
Greg Kroah-Hartman
maintainerPATCH 451/480 Input: touchwin - reset the packet index on every complete packet
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 478cdd736f2ce3114f90e775d7358136d3977b94 upstream.
tw_interrupt() accumulates each non-zero serial byte into a fixed three-byte buffer with a running index that is only reset once a full packet has been received *and* the device's two Y bytes agree:
tw->data[tw->idx++] = data;
if (tw->idx == TW_LENGTH && tw->data[1] == tw->data[2]) {
...
tw->idx = 0;
}The reset is gated on tw->data[1] == tw->data[2], a value the device controls. A malicious, malfunctioning or counterfeit Touchwindow peripheral can stream non-zero bytes whose 2nd and 3rd bytes differ: the index reaches TW_LENGTH without the equality holding, is never reset, and keeps growing, so tw->data[tw->idx++] walks off the end of the three-byte array and the rest of the heap-allocated struct tw, one attacker-chosen byte at a time -- an unbounded, device-driven heap out-of-bounds write.
Reset the index on every completed packet and report an event only when the two Y bytes match, like the other serio touchscreen drivers do.
--- drivers/input/touchscreen/touchwin.c | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-)
drivers/input/touchscreen/touchwin.c +9 -6
@@ -63,12 +63,15 @@ static irqreturn_t tw_interrupt(struct sif (data) {/* touch */ tw->touched =1 ; tw->data[tw->idx++] = data; -/* verify length and that the two Y's are the same */ -if (tw->idx ==TW_LENGTH && tw->data[1 ] == tw->data[2 ]) { -input_report_abs (dev,ABS_X , tw->data[0 ]); -input_report_abs (dev,ABS_Y , tw->data[1 ]); -input_report_key (dev,BTN_TOUCH ,1 ); -input_sync (dev); +/* a full packet ends the accumulation, valid or not */ +if (tw->idx ==TW_LENGTH ) { +/* report only if the two Y's are the same */ +if (tw->data[1 ] == tw->data[2 ]) { +input_report_abs (dev,ABS_X , tw->data[0 ]); +input_report_abs (dev,ABS_Y , tw->data[1 ]); +input_report_key (dev,BTN_TOUCH ,1 ); +input_sync (dev); + } tw->idx =0 ; } }else if (tw->touched) {/* untouch */
Greg Kroah-Hartman
maintainerPATCH 452/480 Input: mms114 - reject an oversized device packet size
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bryam Vargas <[email protected]>
commit 66725039f7090afe14c31bd259e2059a68f04023 upstream.
mms114_interrupt() reads a packet of touch data from the device into a fixed-size on-stack buffer
struct mms114_touch touch[MMS114_MAX_TOUCH];
which holds MMS114_MAX_TOUCH (10) events of MMS114_EVENT_SIZE (8) bytes, i.e. 80 bytes. The length of the I2C read into it is taken verbatim from the device:
packet_size = mms114_read_reg(data, MMS114_PACKET_SIZE); if (packet_size <= 0) goto out; ... error = __mms114_read_reg(data, MMS114_INFORMATION, packet_size, (u8 *)touch);
packet_size is a single device register byte (0x0F) and the only check is the lower bound packet_size <= 0; it is never bounded against the size of touch[]. A malfunctioning, malicious or counterfeit controller (or an attacker tampering with the I2C bus) can report a packet_size of up to 255, so __mms114_read_reg() writes up to 175 bytes past the end of touch[] on the IRQ-thread stack: a stack out-of-bounds write that can overwrite the stack canary, saved registers and the return address.
A well-formed device never reports more than the buffer holds, so reject an oversized packet and drop the report, consistent with the handler's other error paths, rather than reading past the buffer.
--- drivers/input/touchscreen/mms114.c | 6 ++++++ 1 file changed, 6 insertions(+)
drivers/input/touchscreen/mms114.c +6 -0
@@ -236,6 +236,12 @@ static irqreturn_t mms114_interrupt(intif (packet_size <=0 ) goto out; +if (packet_size >sizeof (touch)) { +dev_err (&client->dev,"Invalid packet size %d (max %zu)\n" , + packet_size,sizeof (touch)); + goto out; + } +/* MMS136 has slightly different event size */ if (data->type ==TYPE_MMS134S || data->type ==TYPE_MMS136 ) event_size =MMS136_EVENT_SIZE ;
Greg Kroah-Hartman
maintainerPATCH 453/480 Input: gscps2 - advance receive buffer write index
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Xu Rao <[email protected]>
commit d86d4f8cbb5a55a3b9b86f7b5ab8c4cdda600a3f upstream.
Commit 44f920069911 ("Input: gscps2 - use guard notation when acquiring spinlock") moved the receive loop into gscps2_read_data() and gscps2_report_data().
While moving the code, it preserved the writes to buffer[ps2port->append], but omitted the following producer index update from the original loop:
ps2port->append = (ps2port->append + 1) & BUFFER_SIZE;
As a result, append never advances. Since gscps2_report_data() only reports bytes while act != append, the receive buffer always appears empty and no keyboard or mouse data reaches the serio core.
Restore the omitted index update.
--- drivers/input/serio/gscps2.c | 1 + 1 file changed, 1 insertion(+)
drivers/input/serio/gscps2.c +1 -0
@@ -219,6 +219,7 @@ static void gscps2_read_data(struct gscp ps2port->buffer[ps2port->append].str = status; ps2port->buffer[ps2port->append].data =gscps2_readb_input (ps2port->addr); + ps2port->append = (ps2port->append +1 ) &BUFFER_SIZE ; }while (true); }
Greg Kroah-Hartman
maintainerPATCH 454/480 Input: maplemouse - fix NULL pointer dereference in open()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Florian Fuchs <[email protected]>
commit ee89db004238bd0b034f2a6176e175561658750b upstream.
Commit 555c765b0cc2 ("Input: mouse - drop unnecessary calls to input_set_drvdata") dropped the input_set_drvdata() call in probe because the data appeared to be unused. However, dc_mouse_open() and dc_mouse_close() were using maple_get_drvdata(to_maple_dev(&dev->dev)). This appears to be accessing the data attached to an instance of maple_device structure, while in reality this actually retrieves driver data from the input device's embedded struct device (doing invalid conversion of input device structure to maple device). After input_set_drvdata() was removed, that lookup started returning NULL and opening the input device dereferences mse->mdev.
Restore input_set_drvdata() and convert open() and close() to use input_get_drvdata() so the dependency is no longer hidden.
--- drivers/input/mouse/maplemouse.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/input/mouse/maplemouse.c +3 -2
@@ -48,7 +48,7 @@ static void dc_mouse_callback(struct mapstatic int dc_mouse_open (struct input_dev *dev) { -struct dc_mouse *mse =maple_get_drvdata (to_maple_dev (&dev->dev)); +struct dc_mouse *mse =input_get_drvdata (dev);maple_getcond_callback (mse->mdev, dc_mouse_callback,HZ /50 ,MAPLE_FUNC_MOUSE );
@@ -58,7 +58,7 @@ static int dc_mouse_open(struct input_destatic void dc_mouse_close (struct input_dev *dev) { -struct dc_mouse *mse =maple_get_drvdata (to_maple_dev (&dev->dev)); +struct dc_mouse *mse =input_get_drvdata (dev);maple_getcond_callback (mse->mdev, dc_mouse_callback,0 ,MAPLE_FUNC_MOUSE );
@@ -88,6 +88,7 @@ static int probe_maple_mouse(struct devi mse->dev = input_dev; mse->mdev = mdev; +input_set_drvdata (input_dev, mse); input_dev->evbit[0 ] =BIT_MASK (EV_KEY ) |BIT_MASK (EV_REL ); input_dev->keybit[BIT_WORD (BTN_MOUSE )] =BIT_MASK (BTN_LEFT ) |BIT_MASK (BTN_RIGHT ) |BIT_MASK (BTN_MIDDLE );
Greg Kroah-Hartman
maintainerPATCH 455/480 Input: mms114 - fix multi-touch slot corruption
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit adea84ee6cdea611146c4251d3c1616f5a09feca upstream.
If the touchscreen controller reports a touch ID of 0, the driver calculates the slot ID as touch->id - 1, which underflows to UINT_MAX. This is passed to input_mt_slot() as -1.
Since the input core ignores negative slot values, the active slot remains unchanged. The driver then reports the touch coordinates for the previously active slot, corrupting its state.
Fix this by rejecting touch reports with ID 0.
--- drivers/input/touchscreen/mms114.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/input/touchscreen/mms114.c +1 -1
@@ -165,7 +165,7 @@ static void mms114_process_mt(struct mmsunsigned int x;unsigned int y; -if (touch->id >MMS114_MAX_TOUCH ) { +if (touch->id ==0 || touch->id >MMS114_MAX_TOUCH ) {dev_err (&client->dev,"Wrong touch id (%d)\n" , touch->id);return ; }
Greg Kroah-Hartman
maintainerPATCH 456/480 Input: maple_keyb - set driver data before registering input device
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit 536394ec81419b67d9f4f0028812c4372397be1b upstream.
Set maple driver data before calling input_register_device() to ensure that it is available if the device is opened immediately and the callback is triggered.
--- drivers/input/keyboard/maple_keyb.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
drivers/input/keyboard/maple_keyb.c +2 -2
@@ -166,6 +166,8 @@ static int probe_maple_kbd(struct device kbd->dev = idev;memcpy (kbd->keycode, dc_kbd_keycode,sizeof (kbd->keycode)); +maple_set_drvdata (mdev, kbd); + idev->name = mdev->product_name; idev->evbit[0 ] =BIT (EV_KEY ) |BIT (EV_REP ); idev->keycode = kbd->keycode;
@@ -190,8 +192,6 @@ static int probe_maple_kbd(struct device mdev->driver = mdrv; -maple_set_drvdata (mdev, kbd); -return error; fail_register:
Greg Kroah-Hartman
maintainerPATCH 457/480 Input: maplemouse - set driver data before registering input device
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit 738f24bbbc95dd50cb4229d1ed62a05f29db2bda upstream.
Set maple driver data before calling input_register_device() to ensure that it is available if the device is opened immediately and the callback is triggered.
--- drivers/input/mouse/maplemouse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
drivers/input/mouse/maplemouse.c +3 -1
@@ -88,6 +88,8 @@ static int probe_maple_mouse(struct devi mse->dev = input_dev; mse->mdev = mdev; +maple_set_drvdata (mdev, mse); +input_set_drvdata (input_dev, mse); input_dev->evbit[0 ] =BIT_MASK (EV_KEY ) |BIT_MASK (EV_REL ); input_dev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
@@ -103,12 +105,12 @@ static int probe_maple_mouse(struct devi goto fail_register; mdev->driver = mdrv; -maple_set_drvdata (mdev, mse);return error; fail_register:input_free_device (input_dev); +maple_set_drvdata (mdev,NULL ); fail_nomem:kfree (mse); fail:
Greg Kroah-Hartman
maintainerPATCH 458/480 Input: maplecontrol - set driver data before registering input device
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Dmitry Torokhov <[email protected]>
commit fe938ee497d58c644f6910cfe6ae155f6fb3e523 upstream.
Set maple driver data before calling input_register_device() to ensure that it is available if the device is opened immediately and the callback is triggered.
--- drivers/input/joystick/maplecontrol.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-)
drivers/input/joystick/maplecontrol.c +2 -1
@@ -112,6 +112,8 @@ static int probe_maple_controller(struct pad->dev = idev; pad->mdev = mdev; +maple_set_drvdata (mdev, pad); + idev->open = dc_pad_open; idev->close = dc_pad_close;
@@ -146,7 +148,6 @@ static int probe_maple_controller(struct goto fail; mdev->driver = mdrv; -maple_set_drvdata (mdev, pad);return 0 ;
Greg Kroah-Hartman
maintainerPATCH 459/480 RDMA/rtrs-srv: Bound RDMA-Write length to chunk size in rdma_write_sg
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhenhao Wan <[email protected]>
commit 963af8d97a8c6a117134a8d0db1415e0489200b1 upstream.
When the server answers an RTRS READ, rdma_write_sg() builds the source scatter/gather entry for the IB_WR_RDMA_WRITE that returns data to the peer. Its length is taken directly from the wire descriptor:
plist->length = le32_to_cpu(id->rd_msg->desc[0].len);
rd_msg points into the chunk buffer that the remote peer filled via RDMA-WRITE-WITH-IMM (rtrs_srv_rdma_done() -> process_io_req() -> process_read()), so desc[0].len is attacker-controlled and, before this change, was only rejected when zero. The source address is the fixed chunk start (dma_addr[msg_id]) and the source lkey is the PD-wide local_dma_lkey, which is not tied to the chunk's MR mapping, so the verbs layer does not constrain the transfer length to max_chunk_size. msg_id and off are bounded against queue_depth and max_chunk_size in rtrs_srv_rdma_done(), but desc[0].len is a separate field that was not checked against the chunk size.
A peer that advertises desc[0].len larger than max_chunk_size can make the posted RDMA write read past the chunk's mapped region. The resulting behaviour depends on the IOMMU configuration: with no IOMMU or in passthrough mode the read may extend into memory adjacent to the chunk and be returned to the peer, which can disclose host memory; with a translating IOMMU the out-of-range access is expected to fault and abort the connection. In either case the transfer exceeds what the protocol permits and is driven by a remote peer.
Reject a descriptor length above max_chunk_size, mirroring the existing off >= max_chunk_size bound in rtrs_srv_rdma_done(). Legitimate clients do not exceed it: the client sets desc[0].len to its MR length, which is capped at the negotiated max_io_size (max_chunk_size - MAX_HDR_SIZE).
--- drivers/infiniband/ulp/rtrs/rtrs-srv.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-)
drivers/infiniband/ulp/rtrs/rtrs-srv.c +3 -2
@@ -227,8 +227,9 @@ static int rdma_write_sg(struct rtrs_srv/* WR will fail with length error * if this is 0 */ -if (plist->length ==0 ) { -rtrs_err (s,"Invalid RDMA-Write sg list length 0\n" ); +if (plist->length ==0 || plist->length > max_chunk_size) { +rtrs_err (s,"Invalid RDMA-Write sg list length %u\n" , + plist->length);return -EINVAL ; }
Greg Kroah-Hartman
maintainerPATCH 460/480 RDMA/core: Fix broadcast address falsely detected as local
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Maher Sanalla <[email protected]>
commit 942cd47faa2047b46dfd85745603eba9006973e6 upstream.
When rdma_resolve_addr() is invoked with a broadcast destination on an IPoIB interface, is_dst_local() inspects the resolved route and incorrectly concludes that the address is local. As a result, the resolution fails with -ENODEV.
The issue stems from using '&' to compare rt_type with RTN_LOCAL. The RTN_* values form a sequential enum, not a bitmask (RTN_LOCAL=2, RTN_BROADCAST=3). Thus, "rt_type & RTN_LOCAL" yields a non-zero result for a broadcast route as well.
Replace '&' with '==' when comparing rt_type against RTN_LOCAL.
--- drivers/infiniband/core/addr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/infiniband/core/addr.c +1 -1
@@ -439,7 +439,7 @@ static int addr6_resolve(struct sockaddrstatic bool is_dst_local (const struct dst_entry *dst) {if (dst->ops->family ==AF_INET ) -return !!(dst_rtable (dst)->rt_type &RTN_LOCAL ); +return dst_rtable (dst)->rt_type ==RTN_LOCAL ;else if (dst->ops->family ==AF_INET6 )return !!(dst_rt6_info (dst)->rt6i_flags &RTF_LOCAL );else
Greg Kroah-Hartman
maintainerPATCH 461/480 RDMA/siw: bound Read Response placement to the RREAD length
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Michael Bommarito <[email protected]>
commit 7d29f7e9dbd844cae4d3e559cf78324b9642fd6b upstream.
In drivers/infiniband/sw/siw/siw_qp_rx.c, siw_proc_rresp() places each inbound Read Response DDP segment at sge->laddr + wqe->processed and then accumulates wqe->processed, but it never checks the running total against the sink buffer length on continuation segments. siw_check_sge() resolves and validates the sink memory only on the first fragment (the if (!*mem) branch), and siw_rresp_check_ntoh() compares the cumulative length against wqe->bytes only on the final segment (the !frx->more_ddp_segs guard).
A connected siw peer that answers an outstanding RREAD with Read Response segments that keep the DDP Last flag clear, carrying more total payload than the RREAD requested, drives wqe->processed past the validated sink buffer; the next siw_rx_data() call writes out of bounds at sge->laddr + wqe->processed. siw runs iWARP over ordinary routable TCP, so the peer is the remote end of an established RDMA connection and needs no local privilege.
Bound every segment before placement, exactly as siw_proc_send() and siw_proc_write() already do for their tagged and untagged paths, and terminate the connection with a base-or-bounds DDP error when the Read Response would overrun the sink buffer.
This is the second receive-path length fix for this file. A separate change rejects an MPA FPDU length that underflows the per-fragment remainder in the header decode; that guard does not cover this case, because here each individual segment length is self-consistent and only the accumulated placement offset overruns the buffer.
--- drivers/infiniband/sw/siw/siw_qp_rx.c | 9 +++++++++ 1 file changed, 9 insertions(+)
drivers/infiniband/sw/siw/siw_qp_rx.c +9 -0
@@ -844,6 +844,15 @@ int siw_proc_rresp(struct siw_qp *qp) } mem_p = *mem; +if (unlikely (wqe->processed + srx->fpdu_part_rem > wqe->bytes)) { +siw_dbg_qp (qp,"rresp len: %d + %d > %d\n" , + wqe->processed, srx->fpdu_part_rem, wqe->bytes); + wqe->wc_status =SIW_WC_LOC_LEN_ERR ; +siw_init_terminate (qp,TERM_ERROR_LAYER_DDP , +DDP_ETYPE_TAGGED_BUF , +DDP_ECODE_T_BASE_BOUNDS ,0 ); +return -EINVAL ; + } bytes =min (srx->fpdu_part_rem, srx->skb_new); rv =siw_rx_data (mem_p, srx, &frx->pbl_idx, sge->laddr + wqe->processed, bytes);
Greg Kroah-Hartman
maintainerPATCH 462/480 fuse: back uncached readdir buffers with pages
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Matthew R. Ochs <[email protected]>
commit 4dd6f6d3085a84e74b0a1efec3a05ed0b5125dce upstream.
Commit dabb90391028 ("fuse: increase readdir buffer size") changed fuse_readdir_uncached() to size its temporary buffer from ctx->count. This is useful for overlayfs and other in-kernel callers that use INT_MAX to indicate an unlimited directory read.
The larger buffer is currently supplied as a kvec output argument. For virtiofs, kvec arguments are copied through req->argbuf, which is allocated with kmalloc(..., GFP_ATOMIC). A large uncached readdir buffer can therefore require a multi-megabyte contiguous atomic allocation before the request is queued.
Avoid the large bounce-buffer allocation by backing uncached readdir output with pages and setting out_pages. Transports such as virtiofs can then pass the pages as scatter-gather entries instead of copying the output through argbuf.
Map the pages with vm_map_ram() only while parsing the returned dirents. The existing parser can then continue to use a linear kernel mapping.
[SzM: separate allocation of pages into a helper function]
--- fs/fuse/readdir.c | 85 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 67 insertions(+), 18 deletions(-)
fs/fuse/readdir.c +67 -18
@@ -12,6 +12,7 @@#include <linux/posix_acl.h> #include <linux/pagemap.h> #include <linux/highmem.h> +#include <linux/vmalloc.h> static bool fuse_use_readdirplus (struct inode *dir,struct dir_context *ctx) {
@@ -335,6 +336,43 @@ static int parse_dirplusfile(char *buf,return 0 ; } +static struct page **fuse_readdir_alloc_buf (struct fuse_args_pages *ap,size_t *bufsize) +{ +unsigned int i, nr_alloc, nr_pages =DIV_ROUND_UP (*bufsize,PAGE_SIZE ); +struct page **pages =kcalloc (nr_pages,sizeof (*pages),GFP_KERNEL ); + +if (!pages) +return NULL ; + + nr_alloc =alloc_pages_bulk (GFP_KERNEL , nr_pages, pages); +if (!nr_alloc) + goto free_array; + +if (nr_alloc < nr_pages) { + nr_pages = nr_alloc; + *bufsize = (size_t ) nr_pages <<PAGE_SHIFT ; + } + + ap->folios =fuse_folios_alloc (nr_pages,GFP_KERNEL , &ap->descs); +if (!ap->folios) + goto release_pages; + +for (i =0 ; i < nr_pages; i++) { + ap->folios[i] =page_folio (pages[i]); + ap->descs[i].length =min_t (size_t, *bufsize - (size_t )i *PAGE_SIZE ,PAGE_SIZE ); + } + ap->num_folios = nr_pages; + ap->args.out_pages = true; + +return pages; + +release_pages: +release_pages (pages, nr_pages); +free_array: +kfree (pages); +return NULL ; +} +static int fuse_readdir_uncached (struct file *file,struct dir_context *ctx) {int plus;
@@ -343,18 +381,16 @@ static int fuse_readdir_uncached(structstruct fuse_mount *fm =get_fuse_mount (inode);struct fuse_conn *fc = fm->fc;struct fuse_io_args ia = {}; -struct fuse_args *args = &ia.ap.args; +struct fuse_args_pages *ap = &ia.ap;void *buf;size_t bufsize =clamp ((unsigned int ) ctx->count,PAGE_SIZE , fc->max_pages <<PAGE_SHIFT );u64 attr_version =0 , evict_ctr =0 ;bool locked; +struct page **pages =fuse_readdir_alloc_buf (ap, &bufsize); - buf =kvmalloc (bufsize,GFP_KERNEL ); -if (!buf) +if (!pages)return -ENOMEM ; - args->out_args[0 ].value = buf; - plus =fuse_use_readdirplus (inode, ctx);if (plus) { attr_version =fuse_get_attr_version (fm->fc);
@@ -364,24 +400,37 @@ static int fuse_readdir_uncached(structfuse_read_args_fill (&ia, file, ctx->pos, bufsize,FUSE_READDIR ); } locked =fuse_lock_inode (inode); - res =fuse_simple_request (fm, args); + res =fuse_simple_request (fm, &ap->args);fuse_unlock_inode (inode, locked); -if (res >=0 ) { -if (!res) { -struct fuse_file *ff = file->private_data; - -if (ff->open_flags &FOPEN_CACHE_DIR ) -fuse_readdir_cache_end (file, ctx->pos); - }else if (plus) { - res =parse_dirplusfile (buf, res, file, ctx, attr_version, - evict_ctr); - }else { +if (res <0 ) + goto out; + +if (!res) { +struct fuse_file *ff = file->private_data; + +if (ff->open_flags &FOPEN_CACHE_DIR ) +fuse_readdir_cache_end (file, ctx->pos); + goto out; + } + + buf =vm_map_ram (pages, ap->num_folios,-1 ); +if (!buf) { + res = -ENOMEM ; + }else { +if (plus) + res =parse_dirplusfile (buf, res, file, ctx, attr_version, evict_ctr); +else res =parse_dirfile (buf, res, file, ctx); - } + +vm_unmap_ram (buf, ap->num_folios); } +out: +kfree (ap->folios); +release_pages (pages, ap->num_folios); +kfree (pages); -kvfree (buf);fuse_invalidate_atime (inode); +return res; }
Greg Kroah-Hartman
maintainerPATCH 463/480 fuse: avoid 32-bit prune notification count wrap
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Samuel Moelius <[email protected]>
commit 54243797cedf55447b4c5d560e8cd709900061ae upstream.
FUSE_NOTIFY_PRUNE validates the nodeid payload length with:
size - sizeof(outarg) != outarg.count * sizeof(u64)
On 32-bit kernels, size_t is also 32 bits, so the daemon-controlled count multiplication can wrap. A prune notification with count 0x20000000 and no nodeid payload passes the check, enters the copy loop, and asks the device copy path to read nodeids that are not present in the userspace write buffer. In QEMU this reaches the fuse_copy_fill() BUG_ON(!err) path.
Validate the payload length with array_size() instead. That accepts exactly the same valid messages, but avoids wrapping arithmetic before the copy loop consumes the count.
--- fs/fuse/dev.c | 2 fs/fuse/notify.c | 434 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 435 insertions(+), 1 deletion(-) create mode 100644 fs/fuse/notify.c
fs/fuse/dev.c +1 -1
@@ -2082,7 +2082,7 @@ static int fuse_notify_prune(struct fuseif (err)return err; -if (size -sizeof (outarg) != outarg.count *sizeof (u64)) +if (size -sizeof (outarg) !=array_size (outarg.count,sizeof (u64)))return -EINVAL ;for (; outarg.count; outarg.count -= num) {
fs/fuse/notify.c new file +434 -0
434 lines not on this page · raw message
Greg Kroah-Hartman
maintainerPATCH 464/480 fuse: fix device node leak in cuse_process_init_reply()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Alberto Ruiz <[email protected]>
commit 9fa4f7a53406430ee9982f2f636a15b338185122 upstream.
If device_add() succeeds during CUSE initialization but a subsequent step (cdev_alloc() or cdev_add()) fails, the error path calls put_device() without first calling device_del(). This leaks the devtmpfs entry created by device_add(), leaving a stale /dev/<name> node that persists until reboot.
Since the cuse_conn is never linked into cuse_conntbl on the failure path, cuse_channel_release() sees cc->dev == NULL and skips device_unregister(), so no other code path cleans up the node.
This has several consequences:
- The device name is permanently poisoned: any subsequent attempt to create a CUSE device with the same name hits the stale sysfs entry, device_add() fails, and the new device is aborted.
- The collision manifests as ENODEV returned to userspace with no dmesg diagnostic, making it very difficult to debug.
- The failure is self-perpetuating: once a name is leaked, all future attempts with that name fail identically.
Fix this by introducing an err_dev label that calls device_del() to undo device_add() before falling through to err_unlock. The existing err_unlock path from a device_add() failure correctly skips device_del() since the device was never added.
Testing instructions can be found at the lore link below.
--- fs/fuse/cuse.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
fs/fuse/cuse.c +3 -1
@@ -391,7 +391,7 @@ static void cuse_process_init_reply(stru rc = -ENOMEM ; cdev =cdev_alloc ();if (!cdev) - goto err_unlock; + goto err_dev; cdev->owner =THIS_MODULE ; cdev->ops = &cuse_frontend_fops;
@@ -417,6 +417,8 @@ out: err_cdev:cdev_del (cdev); +err_dev: +device_del (dev); err_unlock:mutex_unlock (&cuse_lock);put_device (dev);
Greg Kroah-Hartman
maintainerPATCH 465/480 fuse: re-lock request before returning from fuse_ref_folio()
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
commit b5befa80fdbe287a98480effed9564712924add5 upstream.
fuse_ref_folio() unlocks the request but does not re-lock it before returning. fuse_chan_abort() can end the request and the async end callback (eg fuse_writepage_free()) can free the args while the subsequent copy chain logic after fuse_ref_folio() accesses them, leading to use-after-free issues.
Fix this by locking the request in fuse_ref_folio() before returning.
--- fs/fuse/dev.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
fs/fuse/dev.c +1 -1
@@ -1106,7 +1106,7 @@ static int fuse_ref_folio(struct fuse_co cs->nr_segs++; cs->len =0 ; -return 0 ; +return lock_request (cs->req); }/*
Greg Kroah-Hartman
maintainerPATCH 466/480 fuse: fix io-uring background queue dispatch on request completion
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
commit 31da059891bd3be9c6e59280b8e1777ead90db34 upstream.
When a background request completes via the io_uring path, the background queue gets flushed to dispatch pending background requests, but this is done before the connection-level background counters (fc->num_background, fc->active_background) are properly accounted, which may reduce effective queue depth to one.
The connection-level counters are decremented in fuse_request_end(), but flush_bg_queue() flushes the /dev/fuse path queue (fc->bg_queue), not the io_uring per-queue bg one, which means pending uring background requests on the queue are never dispatched in this path.
Fix this by accounting the connection-level background counters first before flushing the queue's background queue. Since fuse_request_bg_finish() clears FR_BACKGROUND, fuse_request_end() will skip the background cleanup branch entirely, which avoids any double-decrements; it will call the wake_up(&req->waitq) branch but this is effectively a no-op as background requests have no waiters on req->waitq.
--- fs/fuse/dev.c | 41 ++++++++++++++++++++++++----------------- fs/fuse/dev_uring.c | 1 + fs/fuse/fuse_dev_i.h | 1 + 3 files changed, 26 insertions(+), 17 deletions(-)
fs/fuse/dev.c +24 -17
@@ -447,6 +447,29 @@ static void flush_bg_queue(struct fuse_c } } +void fuse_request_bg_finish (struct fuse_conn *fc,struct fuse_req *req) +{ +lockdep_assert_held (&fc->bg_lock); + +clear_bit (FR_BACKGROUND , &req->flags); +if (fc->num_background == fc->max_background) { + fc->blocked =0 ; +wake_up (&fc->blocked_waitq); + }else if (!fc->blocked) { +/* +* Wake up next waiter, if any. It's okay to use +* waitqueue_active(), as we've already synced up +* fc->blocked with waiters with the wake_up() call +* above. +*/ +if (waitqueue_active (&fc->blocked_waitq)) +wake_up (&fc->blocked_waitq); + } + + fc->num_background--; + fc->active_background--; +} +/* * This function is called when a request is finished. Either a reply * has arrived or it was aborted (and not yet sent) or some error
@@ -479,23 +502,7 @@ void fuse_request_end(struct fuse_req *rWARN_ON (test_bit (FR_SENT , &req->flags));if (test_bit (FR_BACKGROUND , &req->flags)) {spin_lock (&fc->bg_lock); -clear_bit (FR_BACKGROUND , &req->flags); -if (fc->num_background == fc->max_background) { - fc->blocked =0 ; -wake_up (&fc->blocked_waitq); - }else if (!fc->blocked) { -/* -* Wake up next waiter, if any. It's okay to use -* waitqueue_active(), as we've already synced up -* fc->blocked with waiters with the wake_up() call -* above. -*/ -if (waitqueue_active (&fc->blocked_waitq)) -wake_up (&fc->blocked_waitq); - } - - fc->num_background--; - fc->active_background--; +fuse_request_bg_finish (fc, req);flush_bg_queue (fc);spin_unlock (&fc->bg_lock); }else {
fs/fuse/dev_uring.c +1 -0
@@ -90,6 +90,7 @@ static void fuse_uring_req_end(struct fuif (test_bit (FR_BACKGROUND , &req->flags)) { queue->active_background--;spin_lock (&fc->bg_lock); +fuse_request_bg_finish (fc, req);fuse_uring_flush_bg (queue);spin_unlock (&fc->bg_lock); }
fs/fuse/fuse_dev_i.h +1 -0
@@ -59,6 +59,7 @@ unsigned int fuse_req_hash(u64 unique);struct fuse_req *fuse_request_find (struct fuse_pqueue *fpq,u64 unique);void fuse_dev_end_requests (struct list_head *head); +void fuse_request_bg_finish (struct fuse_conn *fc,struct fuse_req *req);void fuse_copy_init (struct fuse_copy_state *cs,bool write,struct iov_iter *iter);
Greg Kroah-Hartman
maintainerPATCH 467/480 fuse: clear intr_entry in fuse_resend and fuse_remove_pending_req
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Ji'an Zhou <[email protected]>
commit f8fce75fedf73ac72aa09163deb8f4291fdcaad2 upstream.
When fuse_resend() moves a request from fpq->processing back to fiq->pending, it sets FR_PENDING and clears FR_SENT but does not remove the requests intr_entry from fiq->interrupts. If the request had FR_INTERRUPTED set from a prior signal, intr_entry remains dangling on fiq->interrupts. When the requesting task then receives a fatal signal, fuse_remove_pending_req() sees FR_PENDING=1, removes the request from fiq->pending and frees it via the refcount path, also without cleaning intr_entry. The stale intr_entry causes use-after-free when fuse_read_interrupt() iterates fiq->interrupts:
- list_del_init(&req->intr_entry) -> UAF write on freed slab
- req->in.h.unique -> UAF read, data leaked to userspace
Remove intr_entry from fiq->interrupts in fuse_resend() for interrupted requests before they are placed back on fiq->pending.
Add a WARN_ON if the intr_entry is not empty on request destruction.
--- fs/fuse/dev.c | 9 +++++++++ 1 file changed, 9 insertions(+)
fs/fuse/dev.c +9 -0
@@ -148,6 +148,7 @@ static struct fuse_req *fuse_request_allstatic void fuse_request_free (struct fuse_req *req) { +WARN_ON (!list_empty (&req->intr_entry));kmem_cache_free (fuse_req_cachep, req); }
@@ -2046,6 +2047,14 @@ static void fuse_resend(struct fuse_connfuse_dev_end_requests (&to_queue);return ; } +/* +* Remove interrupt entries for resent requests to prevent stale +* intr_entry on fiq->interrupts after the request is re-queued. +*/ +list_for_each_entry (req, &to_queue, list) { +if (test_bit (FR_INTERRUPTED , &req->flags)) +list_del_init (&req->intr_entry); + }/* iq and pq requests are both oldest to newest */ list_splice (&to_queue, &fiq->pending);fuse_dev_wake_and_unlock (fiq);
Greg Kroah-Hartman
maintainerPATCH 468/480 fuse-uring: fix EFAULT clobber in fuse_uring_commit
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <[email protected]>
commit 3a0a8bc51a13951c5141262bf770eeea3e0b6228 upstream.
copy_from_user() returns the number of bytes not copied as an unsigned residual on failure (1..sizeof(struct fuse_out_header)). fuse_uring_commit stores that residual in ssize_t err, sets req->out.h.error to -EFAULT, then jumps to out: with err still holding the positive residual.
err = copy_from_user(&req->out.h, &ent->headers->in_out,
sizeof(req->out.h));
if (err) {
req->out.h.error = -EFAULT;
goto out; /* err is the positive residual */
}
...
out:
fuse_uring_req_end(ent, req, err);fuse_uring_req_end() then runs
if (error)
req->out.h.error = error;which overwrites the just-assigned -EFAULT with the positive residual. FUSE callers such as fuse_simple_request() test err < 0 to detect failure, so the positive value is interpreted as success and the caller proceeds with an uninitialised or partial req->out.args.
Fix by assigning err = -EFAULT in the failure branch before jumping to out, so fuse_uring_req_end() receives a negative errno and sets req->out.h.error to -EFAULT.
--- fs/fuse/dev_uring.c | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-)
fs/fuse/dev_uring.c +3 -6
@@ -818,14 +818,11 @@ static void fuse_uring_commit(struct fus {struct fuse_ring *ring = ent->queue->ring;struct fuse_conn *fc = ring->fc; -ssize_t err =0 ; +ssize_t err = -EFAULT ; - err =copy_from_user (&req->out.h, &ent->headers->in_out, -sizeof (req->out.h)); -if (err) { - req->out.h.error = -EFAULT ; +if (copy_from_user (&req->out.h, &ent->headers->in_out, +sizeof (req->out.h))) goto out; - } err =fuse_uring_out_header_has_err (&req->out.h, req, fc);if (err) {
Greg Kroah-Hartman
maintainerPATCH 469/480 fuse-uring: fix data races on ring->ready
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <[email protected]>
commit 46725a0056c884cf58a6897f222892807327d82d upstream.
On weakly-ordered architectures, the store to fiq->ops can be reordered past the store to ring->ready, allowing a CPU that sees ring->ready == true via fuse_uring_ready() to dispatch requests through a stale fiq->ops pointer. Upgrade the store to smp_store_release() and the load in fuse_uring_ready() to smp_load_acquire() so that the preceding WRITE_ONCE(fiq->ops, ...) is visible to any CPU that observes ring->ready == true.
Additionally, fuse_uring_do_register() publishes ring->ready with WRITE_ONCE() but the fast-path check reads it with a plain load. This is a marked-vs-unmarked access that KCSAN will flag. Wrap it in READ_ONCE() to mark it without adding unnecessary ordering.
Also wrap the fc->ring load in fuse_uring_ready() in READ_ONCE() to prevent the compiler from reloading it between the NULL check and the dereference.
--- fs/fuse/dev_uring.c | 4 ++-- fs/fuse/dev_uring_i.h | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-)
fs/fuse/dev_uring.c +2 -2
@@ -992,12 +992,12 @@ static void fuse_uring_do_register(strucfuse_uring_ent_avail (ent, queue);spin_unlock (&queue->lock); -if (!ring->ready) { +if (!READ_ONCE (ring->ready)) {bool ready =is_ring_ready (ring, queue->qid);if (ready) {WRITE_ONCE (fiq->ops, &fuse_io_uring_ops); -WRITE_ONCE (ring->ready, true); +smp_store_release (&ring->ready, true);wake_up_all (&fc->blocked_waitq); } }
fs/fuse/dev_uring_i.h +3 -1
@@ -169,7 +169,9 @@ static inline void fuse_uring_wait_stoppstatic inline bool fuse_uring_ready (struct fuse_conn *fc) { -return fc->ring && fc->ring->ready; +struct fuse_ring *ring =READ_ONCE (fc->ring); + +return ring &&smp_load_acquire (&ring->ready); }#else /* CONFIG_FUSE_IO_URING */
Greg Kroah-Hartman
maintainerPATCH 470/480 fuse-uring: fix moving cancelled entry to ent_in_userspace list
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
commit 198f45eeb9f78b2a2d6d8be95e4e43468eb2c6bc upstream.
fuse_uring_cancel() moves entries that are available (these have no reqs attached) to the ent_in_userspace list. ent_list_request_expired() checks the first entry on ent_in_userspace and dereferences ent->fuse_req unconditionally, which will crash on a cancelled entry that was moved to this list.
Fix this by freeing the entry and dropping queue_refs directly in fuse_uring_cancel(). This is safe because cancel is the cancel handler itself - after io_uring_cmd_done(), no more cancels will be dispatched for this command, and teardown serializes with cancel via queue->lock.
Since cancel now decrements queue_refs, fuse_uring_abort() must no longer gate fuse_uring_abort_end_requests() on queue_refs > 0, as cancelled entries may have already dropped queue_refs while requests are still queued. Remove the gate so abort always flushes requests and stops queues.
--- fs/fuse/dev_uring.c | 6 ++++-- fs/fuse/dev_uring_i.h | 6 +++--- 2 files changed, 7 insertions(+), 5 deletions(-)
fs/fuse/dev_uring.c +4 -2
@@ -512,8 +512,7 @@ static void fuse_uring_cancel(struct io_ queue = ent->queue;spin_lock (&queue->lock);if (ent->state ==FRRS_AVAILABLE ) { - ent->state =FRRS_USERSPACE ; -list_move_tail (&ent->list, &queue->ent_in_userspace); +list_del_init (&ent->list); need_cmd_done = true; ent->cmd =NULL ; }
@@ -522,6 +521,9 @@ static void fuse_uring_cancel(struct io_if (need_cmd_done) {/* no queue lock to avoid lock order issues */ io_uring_cmd_done (cmd, -ENOTCONN , issue_flags); +kfree (ent); +if (atomic_dec_and_test (&queue->ring->queue_refs)) +wake_up_all (&queue->ring->stop_waitq); } }
fs/fuse/dev_uring_i.h +3 -3
@@ -152,10 +152,10 @@ static inline void fuse_uring_abort(struif (ring ==NULL )return ; -if (atomic_read (&ring->queue_refs) >0 ) { -fuse_uring_abort_end_requests (ring); +fuse_uring_abort_end_requests (ring); + +if (atomic_read (&ring->queue_refs) >0 )fuse_uring_stop_queues (ring); - } }static inline void fuse_uring_wait_stopped_queues (struct fuse_conn *fc)
Greg Kroah-Hartman
maintainerPATCH 471/480 fuse-uring: end fuse_req on io-uring cancel task work
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Chris Mason <[email protected]>
commit bea4fe98204b6ce7eb8e29f7bf867dd7619b3ddd upstream.
When io_uring delivers task work with tw.cancel set (PF_EXITING, PF_KTHREAD fallback, or percpu_ref_is_dying on the ring context), fuse_uring_send_in_task() takes the cancel branch, assigns -ECANCELED, and falls through to fuse_uring_send(). That path only flips the entry to FRRS_USERSPACE and completes the io_uring cmd; it never discharges the ring entry's owning reference to the fuse_req that fuse_uring_add_req_to_ring_ent() handed it at dispatch time.
fuse_uring_send_in_task()
tw.cancel == true
err = -ECANCELED
fuse_uring_send(ent, cmd, err, issue_flags)
ent->state = FRRS_USERSPACE
list_move(&ent->list, &queue->ent_in_userspace)
ent->cmd = NULL
io_uring_cmd_done(-ECANCELED)
/* ent->fuse_req still set, req still hashed */The fuse_req stays linked on fpq->processing[hash] and fuse_request_end() is never invoked. The originating syscall thread blocks in D-state in request_wait_answer() until fuse_abort_conn() runs, which can be the entire connection lifetime. For FR_BACKGROUND requests fc->num_background is never decremented either, so repeated cancels inflate the counter until max_background is hit and all later background ops stall. tw.cancel does not imply a connection abort (e.g. a single io_uring worker thread exits while the fuse connection stays up), so this cannot be left for fuse_abort_conn() to clean up.
Ending the req but still routing the entry through fuse_uring_send() is not enough: that leaves a req-less entry on ent_in_userspace, and ent_list_request_expired() dereferences ent->fuse_req unconditionally on the head of that list, which would then NULL-deref.
Fix the cancel branch to release the entry directly. Remove it from the queue, complete the io_uring cmd, end the fuse_req, free the entry, and drop its queue_refs (waking the teardown waiter if it was the last).
--- fs/fuse/dev_uring.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
fs/fuse/dev_uring.c +12 -2
@@ -1226,11 +1226,21 @@ static void fuse_uring_send_in_task(strufuse_uring_next_fuse_req (ent, queue, issue_flags);return ; } +fuse_uring_send (ent, cmd, err, issue_flags); }else { err = -ECANCELED ; - } -fuse_uring_send (ent, cmd, err, issue_flags); +spin_lock (&queue->lock); +list_del_init (&ent->list); +spin_unlock (&queue->lock); + +io_uring_cmd_done (cmd, err, issue_flags); + +fuse_uring_req_end (ent, ent->fuse_req, err); +kfree (ent); +if (atomic_dec_and_test (&queue->ring->queue_refs)) +wake_up_all (&queue->ring->stop_waitq); + } }static struct fuse_ring_queue *fuse_uring_task_to_queue (struct fuse_ring *ring)
Greg Kroah-Hartman
maintainerPATCH 472/480 fuse-uring: Avoid use-after-free in fuse_uring_async_stop_queues
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bernd Schubert <[email protected]>
commit d351da75066955144515cb2f9aa959f24a04287a upstream.
fuse_uring_async_stop_queues() might run when the last reference on ring->queue_refs was already dropped.
In order to avoid an early destruction a reference on struct fuse_conn is now taken before starting fuse_uring_async_stop_queues() and that reference is only released when that delayed work queue terminates.
--- fs/fuse/dev_uring.c | 2 ++ 1 file changed, 2 insertions(+)
fs/fuse/dev_uring.c +2 -0
@@ -462,6 +462,7 @@ static void fuse_uring_async_stop_queues FUSE_URING_TEARDOWN_INTERVAL); }else {wake_up_all (&ring->stop_waitq); +fuse_conn_put (ring->chan->conn); } }
@@ -482,6 +483,7 @@ void fuse_uring_stop_queues(struct fuse_ }if (atomic_read (&ring->queue_refs) >0 ) { +fuse_conn_get (ring->chan->conn); ring->teardown_time = jiffies;INIT_DELAYED_WORK (&ring->async_teardown_work, fuse_uring_async_stop_queues);
Greg Kroah-Hartman
maintainerPATCH 473/480 fuse-uring: Avoid queue->stopped races and set/read that value under lock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bernd Schubert <[email protected]>
commit b70a3aca16934c196f92abb17b01c1647b9bb63c upstream.
There are several readers of queue->stopped that check the value under lock, but fuse_uring_commit_fetch() did not and actually the value was not set under the lock in fuse_uring_abort_end_requests() either. Especially in fuse_uring_commit_fetch it is important to check under a lock, because due to races 'struct fuse_req' might be freed with fuse_request_end, but another thread/cpu might already do teardown work.
--- fs/fuse/dev_uring.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-)
fs/fuse/dev_uring.c +9 -5
@@ -131,10 +131,9 @@ void fuse_uring_abort_end_requests(strucif (!queue)continue ; - queue->stopped = true; -WARN_ON_ONCE (ring->fc->max_background !=UINT_MAX );spin_lock (&queue->lock); + queue->stopped = true;spin_lock (&fc->bg_lock);fuse_uring_flush_bg (queue);spin_unlock (&fc->bg_lock);
@@ -462,7 +461,7 @@ static void fuse_uring_async_stop_queues FUSE_URING_TEARDOWN_INTERVAL); }else {wake_up_all (&ring->stop_waitq); -fuse_conn_put (ring->chan->conn); +fuse_conn_put (ring->fc); } }
@@ -483,7 +482,7 @@ void fuse_uring_stop_queues(struct fuse_ }if (atomic_read (&ring->queue_refs) >0 ) { -fuse_conn_get (ring->chan->conn); +fuse_conn_get (ring->fc); ring->teardown_time = jiffies;INIT_DELAYED_WORK (&ring->async_teardown_work, fuse_uring_async_stop_queues);
@@ -903,10 +902,15 @@ static int fuse_uring_commit_fetch(strucreturn err; fpq = &queue->fpq; -if (!READ_ONCE (fc->connected) ||READ_ONCE (queue->stopped)) +if (!READ_ONCE (fc->connected))return err;spin_lock (&queue->lock); +if (unlikely (queue->stopped)) { +spin_unlock (&queue->lock); +return err; + } +/* Find a request based on the unique ID of the fuse request * This should get revised, as it needs a hash calculation and list * search. And full struct fuse_pqueue is needed (memory overhead).
Greg Kroah-Hartman
maintainerPATCH 474/480 fuse-uring: make a fuse_req on SQE commit only findable after memcpy
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Bernd Schubert <[email protected]>
commit 1efd3d474fc0ba74dfd984249bca78807d739812 upstream.
Bad userspace might try to trick us and send commit SQEs request unique / commit-id of requests that are not even send to fuse-server (io_uring_cmd_done() not called) yet.
fuse_uring_commit_fetch() ends the fuse request when the ring entry has a wrong state, but that could have caused a use-after-free with the memcpy operations in fuse_uring_send_in_task(). In order to avoid such races the call of fuse_uring_add_to_pq() is moved after the copy operations and just before completing the io-uring request - malicious userspace cannot find the request anymore until all prepration work in fuse-client/kernel is completed.
This also moves fuse_uring_add_to_pq() a bit up in the code to avoid a forward declaration. Also not with a preparation commit, to make it easier to back port to older kernels.
--- fs/fuse/dev_uring.c | 33 +++++++++++++++++++-------------- 1 file changed, 19 insertions(+), 14 deletions(-)
fs/fuse/dev_uring.c +19 -14
@@ -718,6 +718,19 @@ static int fuse_uring_prepare_send(strucreturn err; } +/* Used to find the request on SQE commit */ +static void fuse_uring_add_to_pq (struct fuse_ring_ent *ent) +{ +struct fuse_ring_queue *queue = ent->queue; +struct fuse_pqueue *fpq = &queue->fpq; +unsigned int hash; +struct fuse_req *req = ent->fuse_req; + + req->ring_entry = ent; + hash =fuse_req_hash (req->in.h.unique); +list_move_tail (&req->list, &fpq->processing[hash]); +} +/* * Write data to the ring buffer and send the request to userspace, * userspace will read it
@@ -740,6 +753,7 @@ static int fuse_uring_send_next_to_ring( ent->cmd =NULL ; ent->state =FRRS_USERSPACE ;list_move_tail (&ent->list, &queue->ent_in_userspace); +fuse_uring_add_to_pq (ent);spin_unlock (&queue->lock);io_uring_cmd_done (cmd,0 , issue_flags);
@@ -757,19 +771,6 @@ static void fuse_uring_ent_avail(struct ent->state =FRRS_AVAILABLE ; } -/* Used to find the request on SQE commit */ -static void fuse_uring_add_to_pq (struct fuse_ring_ent *ent, -struct fuse_req *req) -{ -struct fuse_ring_queue *queue = ent->queue; -struct fuse_pqueue *fpq = &queue->fpq; -unsigned int hash; - - req->ring_entry = ent; - hash =fuse_req_hash (req->in.h.unique); -list_move_tail (&req->list, &fpq->processing[hash]); -} -/* * Assign a fuse queue entry to the given entry */
@@ -787,10 +788,13 @@ static void fuse_uring_add_req_to_ring_e }clear_bit (FR_PENDING , &req->flags); + +/* Until fuse_uring_add_to_pq() the req is not attached to any list */ +list_del_init (&req->list); + ent->fuse_req = req; ent->state =FRRS_FUSE_REQ ;list_move_tail (&ent->list, &queue->ent_w_req_queue); -fuse_uring_add_to_pq (ent, req); }/* Fetch the next fuse request if available */
@@ -1209,6 +1213,7 @@ static void fuse_uring_send(struct fuse_ ent->state =FRRS_USERSPACE ;list_move_tail (&ent->list, &queue->ent_in_userspace); ent->cmd =NULL ; +fuse_uring_add_to_pq (ent);spin_unlock (&queue->lock);io_uring_cmd_done (cmd, ret, issue_flags);
Greg Kroah-Hartman
maintainerPATCH 475/480 fuse-uring: remove request-less entries from ent_w_req_queue to fix NULL deref
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Joanne Koong <[email protected]>
commit 1c57a69be962d459c5e705f5cb4355b841b3461c upstream.
If a copy into the userspace ring buffer fails, a request will be terminated and fuse_uring_req_end() will set ent->fuse_req to NULL but it will leave the entry on ent_w_req_queue in FRRS_FUSE_REQ state. This can lead to a NULL deref if the request expiration logic scans ent_w_req_queue in the window before the entry is moved off it.
Fix this by taking the entry off ent_w_req_queue and changing its state from FRRS_FUSE_REQ to FRRS_INVALID before terminating the request.
--- fs/fuse/dev_uring.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-)
fs/fuse/dev_uring.c +12 -2
@@ -710,10 +710,20 @@ static int fuse_uring_prepare_send(strucint err; err =fuse_uring_copy_to_ring (ent, req); -if (!err) +if (!err) {set_bit (FR_SENT , &req->flags); -else + }else { +/* +* Copying the request failed. Remove the entry from the +* ent_w_req_queue list and terminate the request +*/ +spin_lock (&ent->queue->lock); +list_del_init (&ent->list); + ent->state =FRRS_INVALID ; +spin_unlock (&ent->queue->lock); +fuse_uring_req_end (ent, req, err); + }return err; }
Greg Kroah-Hartman
maintainerPATCH 476/480 sched/fair: Only update stats for allowed CPUs when looking for dst group
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Adam Li <[email protected]>
commit 82d6e01a0699800efd8b048eb584c907ccb47b7a upstream.
Load imbalance is observed when the workload frequently forks new threads. Due to CPU affinity, the workload can run on CPU 0-7 in the first group, and only on CPU 8-11 in the second group. CPU 12-15 are always idle.
{ 0 1 2 3 4 5 6 7 } {8 9 10 11 12 13 14 15}
* * * * * * * * * * * *
When looking for dst group for newly forked threads, in many times update_sg_wakeup_stats() reports the second group has more idle CPUs than the first group. The scheduler thinks the second group is less busy. Then it selects least busy CPUs among CPU 8-11. Therefore CPU 8-11 can be crowded with newly forked threads, at the same time CPU 0-7 can be idle.
A task may not use all the CPUs in a schedule group due to CPU affinity. Only update schedule group statistics for allowed CPUs.
--- kernel/sched/fair.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
kernel/sched/fair.c +1 -1
@@ -10847,7 +10847,7 @@ static inline void update_sg_wakeup_statif (sd->flags &SD_ASYM_CPUCAPACITY ) sgs->group_misfit_task_load =1 ; -for_each_cpu (i,sched_group_span (group)) { +for_each_cpu_and (i,sched_group_span (group), p->cpus_ptr) {struct rq *rq =cpu_rq (i);unsigned int local;
Greg Kroah-Hartman
maintainerPATCH 477/480 usb: gadget: f_fs: Initialize epfile->in early to fix endpoint direction checks
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Neill Kapron <[email protected]>
commit 82cfd4739011bdc7e87b5d585703427e89ddfaa5 upstream.
When parsing endpoint descriptors, ffs_data_got_descs() generates the eps_addrmap which contains the endpoint direction. However, epfile->in was previously only populated in ffs_func_eps_enable() which executes upon USB host connection. As a result, early userspace ioctls like FUNCTIONFS_DMABUF_ATTACH that run before the host connects would see epfile->in as 0, leading to incorrect DMA directions.
By moving the initialization to ffs_epfiles_create(), epfile->in is accurate before userspace opens the endpoint files.
--- drivers/usb/gadget/function/f_fs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/usb/gadget/function/f_fs.c +1 -1
@@ -2354,6 +2354,7 @@ static int ffs_epfiles_create(struct ffssprintf (epfile->name,"ep%02x" , ffs->eps_addrmap[i]); else sprintf(epfile->name, "ep%u", i); + epfile->in = (ffs->eps_addrmap[i] &USB_ENDPOINT_DIR_MASK ) ?1 :0 ; epfile->dentry =ffs_sb_create_file (ffs->sb, epfile->name, epfile, &ffs_epfile_operations);
@@ -2440,7 +2441,6 @@ static int ffs_func_eps_enable(struct ff ret =usb_ep_enable (ep->ep);if (!ret) { epfile->ep = ep; - epfile->in =usb_endpoint_dir_in (ep->ep->desc); epfile->isoc =usb_endpoint_xfer_isoc (ep->ep->desc); }else {break ;
Greg Kroah-Hartman
maintainerPATCH 478/480 timekeeping: Register default clocksource before taking tk_core.lock
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Mikhail Gavrilov <[email protected]>
commit 8fa30821180a9a19e78e9f4df1c0ba710252801e upstream.
Commit f24df84cbe05 ("time/jiffies: Register jiffies clocksource before usage") moved the jiffies clocksource registration into clocksource_default_clock(), so that it is registered lazily on the first call. __clocksource_register() acquires clocksource_mutex, but the first caller is timekeeping_init(), which invokes clocksource_default_clock() while holding tk_core.lock, a raw spinlock.
Acquiring a sleeping mutex while holding a raw spinlock is invalid.
The default clocksource only has to be registered before tk_setup_internals() consumes its mult/shift/maxadj. Neither clocksource_default_clock(), the ->enable() callback, nor the registration itself need tk_core.lock, so fetch and enable the clock before acquiring the lock. This preserves the "register before usage" ordering while keeping clocksource_mutex out of the raw spinlock section.
clocksource_default_clock() has a second caller, clocksource_done_booting(), which invokes it with clocksource_mutex already held. That path avoids a recursive lock because timekeeping_init() has already run and set cs_jiffies_registered, so the registration is skipped there. This change does not alter that; it only fixes the invalid wait context in timekeeping_init().
--- kernel/time/timekeeping.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-)
kernel/time/timekeeping.c +4 -3
@@ -1825,13 +1825,14 @@ void __init timekeeping_init(void)*/ wall_to_mono =timespec64_sub (boot_offset, wall_time); + clock =clocksource_default_clock (); +if (clock->enable) + clock->enable (clock); +guard (raw_spinlock_irqsave)(&tk_core.lock);ntp_init (); - clock =clocksource_default_clock (); -if (clock->enable) - clock->enable (clock);tk_setup_internals (tks, clock);tk_set_xtime (tks, &wall_time);
Greg Kroah-Hartman
maintainerPATCH 479/480 Bluetooth: 6lowpan: Fix using chan->conn as indication to no remote netdev
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Luiz Augusto von Dentz <[email protected]>
commit d38eaf611839b85ade3dd3db309dbc8aaaaf0095 upstream.
b66774b48dd9 ("Bluetooth: L2CAP: Fix UAF in channel timeout by holding conn ref") don't reset the chan->conn to NULL anymore making the bt# netdev not be remove once the last l2cap_chan_del is removed.
Instead of restoring the original behavior this remove the logic of keeping the interface after the last channel is removed because it never worked as intended and the l2cap_chan_del always detach its l2cap_conn which results in always removing the channel anyway.
--- net/bluetooth/6lowpan.c | 18 +++--------------- 1 file changed, 3 insertions(+), 15 deletions(-)
net/bluetooth/6lowpan.c +3 -15
@@ -777,20 +777,10 @@ static void chan_close_cb(struct l2cap_cstruct lowpan_btle_dev *dev =NULL ;struct lowpan_peer *peer;int err = -ENOENT ; -bool last = false, remove = true; +bool last = false;BT_DBG ("chan %p conn %p" , chan, chan->conn); -if (chan->conn && chan->conn->hcon) { -if (!is_bt_6lowpan (chan->conn->hcon)) -return ; - -/* If conn is set, then the netdev is also there and we should -* not remove it. -*/ - remove = false; - } -spin_lock (&devices_lock);list_for_each_entry_rcu (entry, &bt_6lowpan_devices, list) {
@@ -817,10 +807,8 @@ static void chan_close_cb(struct l2cap_cifdown (dev->netdev); -if (remove) { -INIT_WORK (&entry->delete_netdev, delete_netdev); -schedule_work (&entry->delete_netdev); - } +INIT_WORK (&entry->delete_netdev, delete_netdev); +schedule_work (&entry->delete_netdev); }else {spin_unlock (&devices_lock); }
Greg Kroah-Hartman
maintainerPATCH 480/480 Revert "f2fs: remove non-uptodate folio from the page cache in move_data_block"
In reply to Greg Kroah-Hartman6.18-stable review patch. If anyone has any objections, please let me know.
------------------
From: Zhaoyang Huang <[email protected]>
commit ccaba785821970f422c47770331c7e3271763f17 upstream.
This reverts commit 9609dd704725a40cd63d915f2ab6c44248a44598.
The kernel panics are keeping to be reported especially when the f2fs partition get almost full. By investigation, we find that the reason is one f2fs page got freed to buddy without being deleted from LRU and the root cause is the race happened in [2] which is enrolled by this commit.
There are 3 race processes in this scenario, please find below for their main activities.
The changed code in move_data_block() lets the GC path evict the tail-end folio from the page cache through folio_end_dropbehind(). Once folio_unmap_invalidate() removes the folio from mapping->i_pages, the page-cache references for all pages in the folio are dropped. The folio is then kept alive only by temporary external references, which allows a later split to operate on a folio whose subpages are no longer protected by page-cache references.
After the page-cache references are gone, split_folio_to_order() can split the big folio into individual pages and put the resulting subpages back on the LRU. For tail pages beyond EOF, split removes them from the page cache and drops their page-cache references. A tail page can then remain on the LRU with PG_lru set while holding only the split caller's temporary reference. When free_folio_and_swap_cache() drops that final reference, the page enters the final folio_put() release path.
In parallel, folio_isolate_lru() can observe the same tail page with a non-zero refcount and PG_lru set. It clears PG_lru before taking its own reference. If this races with the final folio_put() from the split path, __folio_put() sees PG_lru already cleared and skips lruvec_del_folio(). The page is then freed back to the allocator while its lru links are still present in the LRU list. A later LRU operation on a neighboring page detects the stale link and reports list corruption.
[1]
[ 22.486082] list_del corruption. next->prev should be fffffffec10e0ac8, but was dead000000000122. (next=fffffffec10e0a88) [ 22.486130] ------------[ cut here ]------------ [ 22.486134] kernel BUG at lib/list_debug.c:67! [ 22.486141] Internal error: Oops - BUG: 00000000f2000800 [#1] SMP [ 22.488502] Tainted: [W]=WARN, [O]=OOT_MODULE [ 22.488506] Hardware name: Spreadtrum UMS9230 1H10 SoC (DT) [ 22.488511] pstate: 604000c5 (nZCv daIF +PAN -UAO -TCO -DIT -SSBS BTYPE=--) [ 22.488517] pc : __list_del_entry_valid_or_report+0x14c/0x154 [ 22.488531] lr : __list_del_entry_valid_or_report+0x14c/0x154 [ 22.488539] sp : ffffffc08006b830 [ 22.488542] x29: ffffffc08006b868 x28: 0000000000003020 x27: 0000000000000000 [ 22.488553] x26: 0000000000000000 x25: 0000000000000004 x24: fffffffec10e0ac0 [ 22.488564] x23: 00000000000000e8 x22: 0000000000000024 x21: dead000000000122 [ 22.488574] x20: fffffffec10e0a88 x19: fffffffec10e0ac8 x18: ffffffc080061060 [ 22.488585] x17: 20747562202c3863 x16: 6130653031636566 x15: 0000000000000058 [ 22.488595] x14: 0000000000000004 x13: ffffff80f91e0000 x12: 0000000000000003 [ 22.488605] x11: 0000000000000003 x10: 0000000000000001 x9 : ffe85721f0e25f00 [ 22.488615] x8 : ffe85721f0e25f00 x7 : 0000000000000000 x6 : 6c65645f7473696c [ 22.488625] x5 : ffffffed39b23026 x4 : 0000000000000000 x3 : 0000000000000010 [ 22.488636] x2 : 0000000000000000 x1 : 0000000000000000 x0 : 000000000000006d [ 22.488647] Call trace: [ 22.488651] __list_del_entry_valid_or_report+0x14c/0x154 (P) [ 22.488661] __folio_put+0x2bc/0x434 [ 22.488670] folio_put+0x28/0x58 [ 22.488678] do_garbage_collect+0x1a34/0x2584 [ 22.488689] f2fs_gc+0x230/0x9b4 [ 22.488697] f2fs_fallocate+0xb90/0xdf4 [ 22.488706] vfs_fallocate+0x1b4/0x2bc [ 22.488716] __arm64_sys_fallocate+0x44/0x78 [ 22.488725] invoke_syscall+0x58/0xe4 [ 22.488732] do_el0_svc+0x48/0xdc [ 22.488739] el0_svc+0x3c/0x98 [ 22.488747] el0t_64_sync_handler+0x20/0x130 [ 22.488754] el0t_64_sync+0x1c4/0x1c8
[2]
CPU0 (f2fs GC) CPU1 (split_folio_to_order) CPU2 (folio_isolate_lru)
F: pagecache refs = n
F: extra refs = GC + split
F: PG_lru setmove_data_block()
folio = f2fs_grab_cache_folio(F)
...__folio_set_dropbehind(F)folio_unlock(F)folio_end_dropbehind(F)
folio_unmap_invalidate(F)
__filemap_remove_folio(F)
folio_put_refs(F, n)folio_put(F)
split_folio_to_order(F)
folio_ref_freeze(F, 1)
...
lru_add_split_folio(T)
list_add_tail(&T->lru, &F->lru)
folio_set_lru(T)
__filemap_remove_folio(T)
folio_put_refs(T, 1)
/* T refcount == 1, PageLRU set */
folio_isolate_lru(T)
folio_test_clear_lru(T)
free_folio_and_swap_cache(T)
folio_put(T)
/* refcount: 1 -> 0 */
__folio_put(T)
__page_cache_release(T)
folio_test_lru(T) == false
/* skip lruvec_del_folio(T) */
free_frozen_pages(T)
folio_get(T)
lruvec_del_folio(T)
later:
list_del(adjacent->lru)
next == &T->lru
next->prev == LIST_POISON / PCP freelist
BUG--- fs/f2fs/gc.c | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-)
fs/f2fs/gc.c +1 -5
@@ -1487,11 +1487,7 @@ up_out: put_out:f2fs_put_dnode (&dn); out: -if (!folio_test_uptodate (folio)) -__folio_set_dropbehind (folio); -folio_unlock (folio); -folio_end_dropbehind (folio); -folio_put (folio); +f2fs_folio_put (folio, true); out_iput:if (atomic_inode)iput (atomic_inode);
# Librecast Test Results
020/020 [ OK ] liblcrq
010/010 [ OK ] libmld
120/120 [ OK ] liblibrecast
CPU/kernel: Linux auntie 6.18.39-rc1-g8b991bdbbd89 #1 SMP PREEMPT_DYNAMIC Thu Jul 16 14:47:15 -00 2026 x86_64 AMD Ryzen 9 9950X 16-Core Processor AuthenticAMD GNU/Linux
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.18.39 release. There are 480 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 18 Jul 2026 13:30:01 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.39-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.18.y
and the diffstat can be found below.thanks,
greg k-h
On ARCH_BRCMSTB using 32-bit and 64-bit ARM kernels, build tested on BMIPS_GENERIC:
Signature · 1 line
Florian
Am 16.07.2026 um 15:25 schrieb Greg Kroah-Hartman:
Quoted 4 lines
This is the start of the stable review cycle for the 6.18.39 release. There are 480 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Builds, boots and works on my 2-socket Ivy Bridge Xeon E5-2697 v2 server. No dmesg oddities or regressions found.
Beste Grüße,
Peter Schneider
Signature · 8 lines
Climb the mountain not to plant your flag, but to embrace the challenge, enjoy the air and behold the view. Climb it so you can see the world, not so the world can see you. -- David McCullough Jr. OpenPGP: 0xA3828BD796CCE11A8CADE8866E3A92C92C3FF244 Download: https://www.peters-netzplatz.de/download/pschneider1968_pub.asc https://keys.mailvelope.com/pks/lookup?op=get&[email protected] https://keys.mailvelope.com/pks/lookup?op=get&[email protected]
Quoted 8 lines · On Thu, 16 Jul 2026 15:25:47 +0200 Greg Kroah-Hartman…
This is the start of the stable review cycle for the 6.18.39 release. There are 480 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 18 Jul 2026 13:30:01 +0000. Anything received after that time might be too late.
Boot-tested under QEMU for Rust x86_64, arm64 and riscv64; built-tested for loongarch64 and arm32:
Thanks!
Cheers,
Miguel
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.18.39 release. There are 480 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 18 Jul 2026 13:30:01 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 8 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.39-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.18.y
and the diffstat can be found below.thanks,
greg k-h
Built and booted successfully on RISC-V RV64 (HiFive Unmatched).
Hi,
Build tested in our x86,arm64,loongarch,riscv config successfully without error.
BRs
Wentao Guan
defconfigs:
https://gist.github.com/opsiff/a840ae9e3d6857f5b7bacb9cdc49f8e9
Log:
Linux version 6.18.39-rc1-g8b991bdbbd89 (guanwentao@uos-PC) (aarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT_DYNAMIC Linux version 6.18.39-rc1-g8b991bdbbd89 (guanwentao@uos-PC) (aarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #2 SMP PREEMPT_DYNAMIC Fri Jul 17 02:48:08 CST 2026 Linux version 6.18.39-rc1-g8b991bdbbd89 (guanwentao@uos-PC) (loongarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT_DYNAMIC Linux version 6.18.39-rc1-g8b991bdbbd89 (guanwentao@uos-PC) (loongarch64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #3 SMP PREEMPT_DYNAMIC Fri Jul 17 03:05:33 CST 2026 Linux version 6.18.39-rc1+ (guanwentao@uos-PC) (riscv64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT
Linux version 6.18.39-rc1+ (guanwentao@uos-PC) (riscv64-linux-gnu-gcc-12 (Deepin 12.3.0-17deepin8) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #4 SMP PREEMPT Fri Jul 17 03:22:05 CST 2026 Linux version 6.18.39-rc1-g8b991bdbbd89 (guanwentao@uos-PC) (gcc (Deepin 12.3.0-17deepin15) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) # SMP PREEMPT_DYNAMIC
Linux version 6.18.39-rc1-g8b991bdbbd89 (guanwentao@uos-PC) (gcc (Deepin 12.3.0-17deepin15) 12.3.0, GNU ld (GNU Binutils for Deepin) 2.41) #1 SMP PREEMPT_DYNAMIC Fri Jul 17 02:27:34 CST 2026
Quoted 9 lines · Greg Kroah-Hartman
This is the start of the stable review cycle for the 6.18.39 release. There are 480 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 18 Jul 2026 13:30:01 +0000. Anything received after that time might be too late.
The whole patch series can be found in one patch at:
Quoted 10 lines
https://www.kernel.org/pub/linux/kernel/v6.x/stable-review/patch-6.18.39-rc1.gzor in the git tree and branch at:
git://git.kernel.org/pub/scm/linux/kernel/git/stable/linux-stable-rc.gitlinux-6.18.y
and the diffstat can be found below.thanks,
greg k-h
Compiled and booted on my test system. No dmesg regressions.
thanks,
-- Shuah
Hi!
Quoted 7 lines
This is the start of the stable review cycle for the 6.18.39 release. There are 480 patches in this series, all will be posted as a response to this one. If anyone has any issues with these being applied, please let me know.
Responses should be made by Sat, 18 Jul 2026 13:30:01 +0000. Anything received after that time might be too late.
CIP testing did not find any problems here:
https://gitlab.com/cip-project/cip-testing/linux-stable-rc-ci/-/tree/linux-6.18.y
Best regards,
Pavel