From 9191906adfd674e6f647b2c3289751de914addac Mon Sep 17 00:00:00 2001 From: Pratyush Brahma Date: Fri, 15 Sep 2023 16:14:49 +0530 Subject: [PATCH 01/15] iommu: Fix missing return check of arm_lpae_init_pte UAF scenario may occur in clients with EL1 privileges for iova mappings when we miss to check the return value of arm_lpae_init_pte which may lead to an PTE be counted as it was set even if it was already existing. This can cause a dangling IOMMU PTE to be left mapped pointing to a freed object and cause UAF in the client if the dangling PTE is accessed after a failed unmap operation. Fixes: 27de1978c331 ("ANDROID: GKI: iommu/io-pgtable-arm: LPAE related updates by vendor") Change-Id: I674b9b520e705b8f8e63ba20ed76e64cb2fe0f47 Signed-off-by: Pratyush Brahma (cherry picked from commit a0ad1961666eaa4b1bba58b57353c3bbf9848b3a) --- drivers/iommu/io-pgtable-arm.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/drivers/iommu/io-pgtable-arm.c b/drivers/iommu/io-pgtable-arm.c index 12fa224ff8b3..f8cfb9382594 100644 --- a/drivers/iommu/io-pgtable-arm.c +++ b/drivers/iommu/io-pgtable-arm.c @@ -683,9 +683,11 @@ static int arm_lpae_map_sg(struct io_pgtable_ops *ops, unsigned long iova, arm_lpae_iopte *ptep = ms.pgtable + ARM_LPAE_LVL_IDX(iova, MAP_STATE_LVL, data); - arm_lpae_init_pte( + ret = arm_lpae_init_pte( data, iova, phys, prot, MAP_STATE_LVL, ptep, ms.prev_pgtable, false); + if (ret) + goto out_err; ms.num_pte++; } else { ret = __arm_lpae_map(data, iova, phys, pgsize, From 4bd2701df001c53dbbeb334eddeb4dd48f252c17 Mon Sep 17 00:00:00 2001 From: Pankaj Gupta Date: Thu, 14 Sep 2023 21:44:26 +0530 Subject: [PATCH 02/15] msm: kgsl: Prevent wrap around during user address mapping When setting svm region during the gpuobj import ioctl call for a usermem address, there is a possibility of a very large input size causing the region's 64-bit end address to wrap around. This can cause the region to incorrectly be considered valid, ultimately allowing a use after free scenario. To prevent this, detect the occurrence of a wrap and reject the import. Change-Id: I4a88f56c58b830d4342e47dc1d1f6290c78ab6b4 Signed-off-by: Mohammed Mirza Mandayappurath Manzoor Signed-off-by: Pankaj Gupta (cherry picked from commit 970275cba23e35055f90d60e3ff643ddb4da84ca) --- drivers/gpu/msm/kgsl_iommu.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/msm/kgsl_iommu.c b/drivers/gpu/msm/kgsl_iommu.c index fc75683dd210..690ffe008811 100644 --- a/drivers/gpu/msm/kgsl_iommu.c +++ b/drivers/gpu/msm/kgsl_iommu.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2011-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -2157,14 +2158,18 @@ static uint64_t kgsl_iommu_find_svm_region(struct kgsl_pagetable *pagetable, static bool iommu_addr_in_svm_ranges(struct kgsl_iommu_pt *pt, u64 gpuaddr, u64 size) { + u64 end = gpuaddr + size; + + /* Make sure size is not zero and we don't wrap around */ + if (end <= gpuaddr) + return false; + if ((gpuaddr >= pt->compat_va_start && gpuaddr < pt->compat_va_end) && - ((gpuaddr + size) > pt->compat_va_start && - (gpuaddr + size) <= pt->compat_va_end)) + (end > pt->compat_va_start && end <= pt->compat_va_end)) return true; if ((gpuaddr >= pt->svm_start && gpuaddr < pt->svm_end) && - ((gpuaddr + size) > pt->svm_start && - (gpuaddr + size) <= pt->svm_end)) + (end > pt->svm_start && end <= pt->svm_end)) return true; return false; From 1a7ef034b3a2c2b702eda9cc9b80806c1d0164c8 Mon Sep 17 00:00:00 2001 From: Kaushal Sanadhya Date: Fri, 15 Sep 2023 11:35:16 +0530 Subject: [PATCH 03/15] msm: kgsl: Limit the syncpoint count for AUX commands KGSL internally has a limit on the length of the list of syncpoints submitted in a single AUX command. Enforce this limit so we don't overwrite memory beyond the structures that track these syncpoints. Change-Id: I261bfd4f786ff7e4fbe07e8bca9e9b8d8b87c950 Signed-off-by: Lynus Vaz Signed-off-by: Kaushal Sanadhya (cherry picked from commit 77799976865f3eb9c60efcf529434c0b64f9f3e4) --- drivers/gpu/msm/kgsl.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 0a311a79bfb9..964b8536666b 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -2038,6 +2038,10 @@ long kgsl_ioctl_gpu_aux_command(struct kgsl_device_private *dev_priv, (KGSL_GPU_AUX_COMMAND_TIMELINE))) return -EINVAL; + if ((param->flags & KGSL_GPU_AUX_COMMAND_SYNC) && + (param->numsyncs > KGSL_MAX_SYNCPOINTS)) + return -EINVAL; + context = kgsl_context_get_owner(dev_priv, param->context_id); if (!context) return -EINVAL; From 1e8b9e570dc43cb4b43c86a5dc7a6a904c517f79 Mon Sep 17 00:00:00 2001 From: Saranya R Date: Thu, 31 Aug 2023 16:40:12 +0530 Subject: [PATCH 04/15] Configured process_madvise with upstream syscall number Fixing the syscall mapping which was done wrongly by 'commit f4ed73112f31 ("mm/madvise: introduce process_madvise() syscall: an external memory hinting API")' by correcting the syscall number. unistd#close_range cts testcase is expecting errno as ENOSYS because msm-5.4 does not support close_range syscall, but it receives errno as EINVAL because process_madvise is configured with 436 which is close_range syscall number which leads to this cts testcase failure. Hence, configured process_madvise with proper upstream syscall number to fix this cts failure. Applications using process_madvise that are built with previous headers needs to be rebuilt. Otherwise the program would not work as expected. Change-Id: If524d109aa1f4072e9ed03d7d9f70cc517fd59dc Signed-off-by: Saranya R (cherry picked from commit ab1865af0cd4cae64828f62866db4fd7a99ab504) --- arch/alpha/kernel/syscalls/syscall.tbl | 6 +++++- arch/arm/tools/syscall.tbl | 6 +++++- arch/arm64/include/asm/unistd.h | 2 +- arch/arm64/include/asm/unistd32.h | 2 +- arch/ia64/kernel/syscalls/syscall.tbl | 6 +++++- arch/m68k/kernel/syscalls/syscall.tbl | 6 +++++- arch/microblaze/kernel/syscalls/syscall.tbl | 6 +++++- arch/mips/kernel/syscalls/syscall_n32.tbl | 6 +++++- arch/mips/kernel/syscalls/syscall_n64.tbl | 6 +++++- arch/parisc/kernel/syscalls/syscall.tbl | 6 +++++- arch/powerpc/kernel/syscalls/syscall.tbl | 6 +++++- arch/s390/kernel/syscalls/syscall.tbl | 6 +++++- arch/sh/kernel/syscalls/syscall.tbl | 6 +++++- arch/sparc/kernel/syscalls/syscall.tbl | 6 +++++- arch/x86/entry/syscalls/syscall_32.tbl | 6 +++++- arch/x86/entry/syscalls/syscall_64.tbl | 6 +++++- arch/xtensa/kernel/syscalls/syscall.tbl | 6 +++++- include/uapi/asm-generic/unistd.h | 4 ++-- 18 files changed, 79 insertions(+), 19 deletions(-) diff --git a/arch/alpha/kernel/syscalls/syscall.tbl b/arch/alpha/kernel/syscalls/syscall.tbl index 517820726be1..7a04003bfcb4 100644 --- a/arch/alpha/kernel/syscalls/syscall.tbl +++ b/arch/alpha/kernel/syscalls/syscall.tbl @@ -475,4 +475,8 @@ 543 common fspick sys_fspick 544 common pidfd_open sys_pidfd_open # 545 reserved for clone3 -546 common process_madvise sys_process_madvise +# 546 reserved for close_range +# 547 reserved for openat2 +# 548 reserved for pidfd_getfd +# 549 reserved for faccessat2 +550 common process_madvise sys_process_madvise diff --git a/arch/arm/tools/syscall.tbl b/arch/arm/tools/syscall.tbl index d98b34066200..b7eb74edf569 100644 --- a/arch/arm/tools/syscall.tbl +++ b/arch/arm/tools/syscall.tbl @@ -449,4 +449,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open 435 common clone3 sys_clone3 -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h index febc1aa57714..b3b2019f8d16 100644 --- a/arch/arm64/include/asm/unistd.h +++ b/arch/arm64/include/asm/unistd.h @@ -38,7 +38,7 @@ #define __ARM_NR_compat_set_tls (__ARM_NR_COMPAT_BASE + 5) #define __ARM_NR_COMPAT_END (__ARM_NR_COMPAT_BASE + 0x800) -#define __NR_compat_syscalls 437 +#define __NR_compat_syscalls 441 #endif #define __ARCH_WANT_SYS_CLONE diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h index c885dcfcd605..52879c7aaa54 100644 --- a/arch/arm64/include/asm/unistd32.h +++ b/arch/arm64/include/asm/unistd32.h @@ -879,7 +879,7 @@ __SYSCALL(__NR_fspick, sys_fspick) __SYSCALL(__NR_pidfd_open, sys_pidfd_open) #define __NR_clone3 435 __SYSCALL(__NR_clone3, sys_clone3) -#define __NR_process_madvise 436 +#define __NR_process_madvise 440 __SYSCALL(__NR_process_madvise, sys_process_madvise) /* diff --git a/arch/ia64/kernel/syscalls/syscall.tbl b/arch/ia64/kernel/syscalls/syscall.tbl index ec028e67cda4..6915e787a037 100644 --- a/arch/ia64/kernel/syscalls/syscall.tbl +++ b/arch/ia64/kernel/syscalls/syscall.tbl @@ -356,4 +356,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open # 435 reserved for clone3 -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/m68k/kernel/syscalls/syscall.tbl b/arch/m68k/kernel/syscalls/syscall.tbl index ac37a032eb1f..95cc3b9d40ef 100644 --- a/arch/m68k/kernel/syscalls/syscall.tbl +++ b/arch/m68k/kernel/syscalls/syscall.tbl @@ -435,4 +435,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open # 435 reserved for clone3 -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/microblaze/kernel/syscalls/syscall.tbl b/arch/microblaze/kernel/syscalls/syscall.tbl index 9ea93304751e..0bf9a04e19b5 100644 --- a/arch/microblaze/kernel/syscalls/syscall.tbl +++ b/arch/microblaze/kernel/syscalls/syscall.tbl @@ -441,4 +441,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open 435 common clone3 sys_clone3 -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/mips/kernel/syscalls/syscall_n32.tbl b/arch/mips/kernel/syscalls/syscall_n32.tbl index 2af8bfac917e..6ae6842599ac 100644 --- a/arch/mips/kernel/syscalls/syscall_n32.tbl +++ b/arch/mips/kernel/syscalls/syscall_n32.tbl @@ -374,4 +374,8 @@ 433 n32 fspick sys_fspick 434 n32 pidfd_open sys_pidfd_open 435 n32 clone3 __sys_clone3 -436 n32 process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 n32 process_madvise sys_process_madvise diff --git a/arch/mips/kernel/syscalls/syscall_n64.tbl b/arch/mips/kernel/syscalls/syscall_n64.tbl index 2074bfcb61ac..6a663f85820c 100644 --- a/arch/mips/kernel/syscalls/syscall_n64.tbl +++ b/arch/mips/kernel/syscalls/syscall_n64.tbl @@ -350,4 +350,8 @@ 433 n64 fspick sys_fspick 434 n64 pidfd_open sys_pidfd_open 435 n64 clone3 __sys_clone3 -436 n64 process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 n64 process_madvise sys_process_madvise diff --git a/arch/parisc/kernel/syscalls/syscall.tbl b/arch/parisc/kernel/syscalls/syscall.tbl index 920d4c17a672..32347996e8e0 100644 --- a/arch/parisc/kernel/syscalls/syscall.tbl +++ b/arch/parisc/kernel/syscalls/syscall.tbl @@ -433,4 +433,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open 435 common clone3 sys_clone3_wrapper -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/powerpc/kernel/syscalls/syscall.tbl b/arch/powerpc/kernel/syscalls/syscall.tbl index 4675cd96f132..f3b2b0c58abb 100644 --- a/arch/powerpc/kernel/syscalls/syscall.tbl +++ b/arch/powerpc/kernel/syscalls/syscall.tbl @@ -517,4 +517,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open 435 nospu clone3 ppc_clone3 -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/s390/kernel/syscalls/syscall.tbl b/arch/s390/kernel/syscalls/syscall.tbl index d30228a28524..3c7aa43482b9 100644 --- a/arch/s390/kernel/syscalls/syscall.tbl +++ b/arch/s390/kernel/syscalls/syscall.tbl @@ -438,4 +438,8 @@ 433 common fspick sys_fspick sys_fspick 434 common pidfd_open sys_pidfd_open sys_pidfd_open 435 common clone3 sys_clone3 sys_clone3 -443 common process_madvise sys_process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise sys_process_madvise diff --git a/arch/sh/kernel/syscalls/syscall.tbl b/arch/sh/kernel/syscalls/syscall.tbl index ebdaf971c3d7..5a4b36ba71c4 100644 --- a/arch/sh/kernel/syscalls/syscall.tbl +++ b/arch/sh/kernel/syscalls/syscall.tbl @@ -438,4 +438,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open # 435 reserved for clone3 -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/sparc/kernel/syscalls/syscall.tbl b/arch/sparc/kernel/syscalls/syscall.tbl index 9dc5e4581e33..4822c37f044c 100644 --- a/arch/sparc/kernel/syscalls/syscall.tbl +++ b/arch/sparc/kernel/syscalls/syscall.tbl @@ -481,4 +481,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open # 435 reserved for clone3 -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/arch/x86/entry/syscalls/syscall_32.tbl b/arch/x86/entry/syscalls/syscall_32.tbl index 93dc19bc9394..3b161e17479e 100644 --- a/arch/x86/entry/syscalls/syscall_32.tbl +++ b/arch/x86/entry/syscalls/syscall_32.tbl @@ -440,4 +440,8 @@ 433 i386 fspick sys_fspick __ia32_sys_fspick 434 i386 pidfd_open sys_pidfd_open __ia32_sys_pidfd_open 435 i386 clone3 sys_clone3 __ia32_sys_clone3 -436 i386 process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 i386 process_madvise sys_process_madvise diff --git a/arch/x86/entry/syscalls/syscall_64.tbl b/arch/x86/entry/syscalls/syscall_64.tbl index a0908fff28e8..9ebbe98df765 100644 --- a/arch/x86/entry/syscalls/syscall_64.tbl +++ b/arch/x86/entry/syscalls/syscall_64.tbl @@ -357,7 +357,11 @@ 433 common fspick __x64_sys_fspick 434 common pidfd_open __x64_sys_pidfd_open 435 common clone3 __x64_sys_clone3/ptregs -436 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise # # x32-specific system call numbers start at 512 to avoid cache impact diff --git a/arch/xtensa/kernel/syscalls/syscall.tbl b/arch/xtensa/kernel/syscalls/syscall.tbl index 0303a5c0952d..efb08d731a01 100644 --- a/arch/xtensa/kernel/syscalls/syscall.tbl +++ b/arch/xtensa/kernel/syscalls/syscall.tbl @@ -406,4 +406,8 @@ 433 common fspick sys_fspick 434 common pidfd_open sys_pidfd_open 435 common clone3 sys_clone3 -443 common process_madvise sys_process_madvise +# 436 reserved for close_range +# 437 reserved for openat2 +# 438 reserved for pidfd_getfd +# 439 reserved for faccessat2 +440 common process_madvise sys_process_madvise diff --git a/include/uapi/asm-generic/unistd.h b/include/uapi/asm-generic/unistd.h index 619fdf93772e..674a0b04693c 100644 --- a/include/uapi/asm-generic/unistd.h +++ b/include/uapi/asm-generic/unistd.h @@ -850,11 +850,11 @@ __SYSCALL(__NR_pidfd_open, sys_pidfd_open) #define __NR_clone3 435 __SYSCALL(__NR_clone3, sys_clone3) #endif -#define __NR_process_madvise 436 +#define __NR_process_madvise 440 __SYSCALL(__NR_process_madvise, sys_process_madvise) #undef __NR_syscalls -#define __NR_syscalls 437 +#define __NR_syscalls 441 /* * 32 bit systems traditionally used different From 9f528ac044e8362821f149177ca255f96eddb4d0 Mon Sep 17 00:00:00 2001 From: Ravi Kumar Bokka Date: Tue, 5 Sep 2023 14:05:00 +0530 Subject: [PATCH 05/15] securemsm-kernel: Fix multiple listener registration on same fd Currently, multiple listeners can register on same fd which could lead to potential vulnerabilities of use after free while unregistering the listener. Add check to prevent more than one listener registration on a fd. Change-Id: Ia2973853943b5619bcf2047629b9c193f6a8c5cf Signed-off-by: Pawan Rai Signed-off-by: Ravi Kumar Bokka (cherry picked from commit e47d921a39f1c84a2ba61cae477c917917c7335f) --- drivers/misc/qseecom.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/drivers/misc/qseecom.c b/drivers/misc/qseecom.c index 8c338aaa615c..2eeabe55d6ca 100644 --- a/drivers/misc/qseecom.c +++ b/drivers/misc/qseecom.c @@ -378,7 +378,7 @@ struct qseecom_client_handle { struct qseecom_listener_handle { u32 id; - bool unregister_pending; + bool register_pending; bool release_called; }; @@ -1550,6 +1550,11 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, struct qseecom_registered_listener_list *new_entry; struct qseecom_registered_listener_list *ptr_svc; + if (data->listener.register_pending) { + pr_err("Already a listner registration is in process on this FD\n"); + return -EINVAL; + } + ret = copy_from_user(&rcvd_lstnr, argp, sizeof(rcvd_lstnr)); if (ret) { pr_err("copy_from_user failed\n"); @@ -1559,6 +1564,13 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, rcvd_lstnr.sb_size)) return -EFAULT; + ptr_svc = __qseecom_find_svc(data->listener.id); + if (ptr_svc) { + pr_err("Already a listener registered on this data: lid=%d\n", + data->listener.id); + return -EINVAL; + } + ptr_svc = __qseecom_find_svc(rcvd_lstnr.listener_id); if (ptr_svc) { if (!ptr_svc->unregister_pending) { @@ -1602,13 +1614,16 @@ static int qseecom_register_listener(struct qseecom_dev_handle *data, new_entry->svc.listener_id = rcvd_lstnr.listener_id; new_entry->sb_length = rcvd_lstnr.sb_size; new_entry->user_virt_sb_base = rcvd_lstnr.virt_sb_base; + data->listener.register_pending = true; if (__qseecom_set_sb_memory(new_entry, data, &rcvd_lstnr)) { pr_err("qseecom_set_sb_memory failed for listener %d, size %d\n", rcvd_lstnr.listener_id, rcvd_lstnr.sb_size); __qseecom_free_tzbuf(&new_entry->sglistinfo_shm); kzfree(new_entry); + data->listener.register_pending = false; return -ENOMEM; } + data->listener.register_pending = false; init_waitqueue_head(&new_entry->rcv_req_wq); init_waitqueue_head(&new_entry->listener_block_app_wq); From 36e68ff50cb5dbc525599233e5a4faeb5c25c69a Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Wed, 27 Sep 2023 15:52:56 +0530 Subject: [PATCH 06/15] ALSA: compress: allow pause and resume during draining With a stream with low bitrate, user can't pause or resume the stream near the end of the stream because current ALSA doesn't allow it. If the stream has very low bitrate enough to store whole stream into the buffer, user can't do anything except stop the stream and then restart it from the first because most of applications call draining after sending last frame to the kernel. If pause, resume are allowed during draining, user experience can be enhanced. To prevent malfunction in HW drivers which don't support pause during draining, pause during draining will only work if HW driver enable this feature explicitly by calling snd_compr_use_pause_in_draining(). Signed-off-by: Gyeongtaek Lee Acked-by: Vinod Koul Link: https://lore.kernel.org/r/000101d6c3f0$89b312b0$9d193810$@samsung.com Change-Id: I480caca000544c4033cdf2d445598e31754d8e5e Signed-off-by: Takashi Iwai Git-commit: 9be9f2d3d073ef42127475f4fb6a392ab133f629 Git-repo: https://android.googlesource.com/kernel/common/ [quic_c_smanag@quicinc.com: resolve trivial merge conflicts] Signed-off-by: Soumya Managoli --- include/sound/compress_driver.h | 16 ++++++++++++++ sound/core/compress_offload.c | 39 ++++++++++++++++++++++++++------- 2 files changed, 47 insertions(+), 8 deletions(-) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index e9a34ca60703..8af183843c73 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -59,6 +59,7 @@ struct snd_compr_runtime { * @direction: stream direction, playback/recording * @metadata_set: metadata set flag, true when set * @next_track: has userspace signal next track transition, true when set + * @pause_in_draining: paused during draining state, true when set * @private_data: pointer to DSP private data */ struct snd_compr_stream { @@ -70,6 +71,7 @@ struct snd_compr_stream { enum snd_compr_direction direction; bool metadata_set; bool next_track; + bool pause_in_draining; void *private_data; #ifdef CONFIG_AUDIO_QGKI struct snd_soc_pcm_runtime *be; @@ -140,6 +142,7 @@ struct snd_compr_ops { * @direction: Playback or capture direction * @lock: device lock * @device: device id + * @use_pause_in_draining: allow pause in draining, true when set */ struct snd_compr { const char *name; @@ -150,6 +153,7 @@ struct snd_compr { unsigned int direction; struct mutex lock; int device; + bool use_pause_in_draining; #ifdef CONFIG_SND_VERBOSE_PROCFS /* private: */ char id[64]; @@ -164,6 +168,18 @@ int snd_compress_deregister(struct snd_compr *device); int snd_compress_new(struct snd_card *card, int device, int type, const char *id, struct snd_compr *compr); +/** + * snd_compr_use_pause_in_draining - Allow pause and resume in draining state + * @substream: compress substream to set + * + * Allow pause and resume in draining state. + * Only HW driver supports this transition can call this API. + */ +static inline void snd_compr_use_pause_in_draining(struct snd_compr_stream *substream) +{ + substream->device->use_pause_in_draining = true; +} + /* dsp driver callback apis * For playback: driver should call snd_compress_fragment_elapsed() to let the * framework know that a fragment has been consumed from the ring buffer diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 4f3fb5ce4b31..ecdb928775a6 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c @@ -698,11 +698,22 @@ static int snd_compr_pause(struct snd_compr_stream *stream) { int retval; - if (stream->runtime->state != SNDRV_PCM_STATE_RUNNING) + switch (stream->runtime->state) { + case SNDRV_PCM_STATE_RUNNING: + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); + if (!retval) + stream->runtime->state = SNDRV_PCM_STATE_PAUSED; + break; + case SNDRV_PCM_STATE_DRAINING: + if (!stream->device->use_pause_in_draining) + return -EPERM; + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); + if (!retval) + stream->pause_in_draining = true; + break; + default: return -EPERM; - retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_PUSH); - if (!retval) - stream->runtime->state = SNDRV_PCM_STATE_PAUSED; + } return retval; } @@ -710,11 +721,22 @@ static int snd_compr_resume(struct snd_compr_stream *stream) { int retval; - if (stream->runtime->state != SNDRV_PCM_STATE_PAUSED) + switch (stream->runtime->state) { + case SNDRV_PCM_STATE_PAUSED: + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); + if (!retval) + stream->runtime->state = SNDRV_PCM_STATE_RUNNING; + break; + case SNDRV_PCM_STATE_DRAINING: + if (!stream->pause_in_draining) + return -EPERM; + retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); + if (!retval) + stream->pause_in_draining = false; + break; + default: return -EPERM; - retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_PAUSE_RELEASE); - if (!retval) - stream->runtime->state = SNDRV_PCM_STATE_RUNNING; + } return retval; } @@ -754,6 +776,7 @@ static int snd_compr_stop(struct snd_compr_stream *stream) retval = stream->ops->trigger(stream, SNDRV_PCM_TRIGGER_STOP); if (!retval) { + stream->pause_in_draining = false; snd_compr_drain_notify(stream); stream->runtime->total_bytes_available = 0; stream->runtime->total_bytes_transferred = 0; From 7eef634530d2a00fd3992aa26a3845b09d37fe21 Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Mon, 27 Nov 2023 06:53:01 -0800 Subject: [PATCH 07/15] msm: kgsl: Do not free sharedmem if it cannot be unmapped If sharedmem cannot be unmapped from the mmu, it can still be accessed by the GPU. Therefore it is not safe to free the backing memory. In the case that unmap fails, do not free it or return it to the system. Change-Id: Iad3e86d043f129a4d71cf862865d9033d4a315e3 Signed-off-by: Lynus Vaz (cherry picked from commit 330843f54465ee9b62e1a1e2f6c5d12b14c3b548) --- drivers/gpu/msm/kgsl_mmu.c | 2 ++ drivers/gpu/msm/kgsl_sharedmem.c | 24 ++++++++++++++++++++++-- 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/msm/kgsl_mmu.c b/drivers/gpu/msm/kgsl_mmu.c index 2633b72f18f7..33fcaabf838d 100644 --- a/drivers/gpu/msm/kgsl_mmu.c +++ b/drivers/gpu/msm/kgsl_mmu.c @@ -483,6 +483,8 @@ kgsl_mmu_unmap(struct kgsl_pagetable *pagetable, size = kgsl_memdesc_footprint(memdesc); ret = pagetable->pt_ops->mmu_unmap(pagetable, memdesc); + if (ret) + return ret; atomic_dec(&pagetable->stats.entries); atomic_long_sub(size, &pagetable->stats.mapped); diff --git a/drivers/gpu/msm/kgsl_sharedmem.c b/drivers/gpu/msm/kgsl_sharedmem.c index ae66f3acba30..d77ec299ae04 100644 --- a/drivers/gpu/msm/kgsl_sharedmem.c +++ b/drivers/gpu/msm/kgsl_sharedmem.c @@ -1,6 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2002,2007-2021, The Linux Foundation. All rights reserved. + * Copyright (c) 2023 Qualcomm Innovation Center, Inc. All rights reserved. */ #include @@ -948,6 +949,9 @@ static void kgsl_contiguous_free(struct kgsl_memdesc *memdesc) if (!memdesc->hostptr) return; + if (memdesc->priv & KGSL_MEMDESC_MAPPED) + return; + atomic_long_sub(memdesc->size, &kgsl_driver.stats.coherent); #ifdef CONFIG_MM_STAT_UNRECLAIMABLE_PAGES @@ -963,9 +967,14 @@ static void kgsl_free_secure_system_pages(struct kgsl_memdesc *memdesc) { int i; struct scatterlist *sg; - int ret = unlock_sgt(memdesc->sgt); + int ret; int order = get_order(PAGE_SIZE); + if (memdesc->priv & KGSL_MEMDESC_MAPPED) + return; + + ret = unlock_sgt(memdesc->sgt); + if (ret) { /* * Unlock of the secure buffer failed. This buffer will @@ -998,7 +1007,12 @@ static void kgsl_free_secure_system_pages(struct kgsl_memdesc *memdesc) static void kgsl_free_secure_pool_pages(struct kgsl_memdesc *memdesc) { - int ret = unlock_sgt(memdesc->sgt); + int ret; + + if (memdesc->priv & KGSL_MEMDESC_MAPPED) + return; + + ret = unlock_sgt(memdesc->sgt); if (ret) { /* @@ -1028,6 +1042,9 @@ static void kgsl_free_pool_pages(struct kgsl_memdesc *memdesc) kgsl_paged_unmap_kernel(memdesc); WARN_ON(memdesc->hostptr); + if (memdesc->priv & KGSL_MEMDESC_MAPPED) + return; + atomic_long_sub(memdesc->size, &kgsl_driver.stats.page_alloc); kgsl_pool_free_pages(memdesc->pages, memdesc->page_count); @@ -1045,6 +1062,9 @@ static void kgsl_free_system_pages(struct kgsl_memdesc *memdesc) kgsl_paged_unmap_kernel(memdesc); WARN_ON(memdesc->hostptr); + if (memdesc->priv & KGSL_MEMDESC_MAPPED) + return; + atomic_long_sub(memdesc->size, &kgsl_driver.stats.page_alloc); for (i = 0; i < memdesc->page_count; i++) { From 4852a696ac44cc95a60cca5613901b91588f09df Mon Sep 17 00:00:00 2001 From: Vikash Garodia Date: Wed, 29 Nov 2023 09:32:28 +0530 Subject: [PATCH 08/15] BACKPORT: media: venus: hfi: fix the check in session buffer requirement Buffer requirement, for different buffer type, comes from video firmware. While copying these requirements, there is an OOB possibility when the payload from firmware is more than expected size. Fix the check to avoid the OOB possibility. cherry picked from b18e36dfd6c9 ("media: venus: hfi: fix the check to handle session buffer requirement"). Change-Id: I8169c57b2c244c52bac0b4de460b9820707f6ff7 Cc: stable@vger.kernel.org Fixes: 09c2845e8fe4 ("[media] media: venus: hfi: add Host Firmware Interface (HFI)") Reviewed-by: Nathan Hebert Signed-off-by: Stanimir Varbanov Signed-off-by: Hans Verkuil Signed-off-by: Vikash Garodia --- drivers/media/platform/qcom/venus/hfi_msgs.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/media/platform/qcom/venus/hfi_msgs.c b/drivers/media/platform/qcom/venus/hfi_msgs.c index 04ef2286efc6..5694d18b43d5 100644 --- a/drivers/media/platform/qcom/venus/hfi_msgs.c +++ b/drivers/media/platform/qcom/venus/hfi_msgs.c @@ -350,7 +350,7 @@ session_get_prop_buf_req(struct hfi_msg_session_property_info_pkt *pkt, memcpy(&bufreq[idx], buf_req, sizeof(*bufreq)); idx++; - if (idx > HFI_BUFFER_TYPE_MAX) + if (idx >= HFI_BUFFER_TYPE_MAX) return HFI_ERR_SESSION_INVALID_PARAMETER; req_bytes -= sizeof(struct hfi_buffer_requirements); From 04c44a07128c153fd9699a9b3b9b2420f70052b8 Mon Sep 17 00:00:00 2001 From: Soumya Managoli Date: Tue, 16 Jan 2024 11:31:11 +0530 Subject: [PATCH 09/15] ALSA: compress: Remove redefinition Remove redefinition. Signed-off-by: Soumya Managoli Change-Id: I1d6ddff474a38747280f60037342f6f3b4c295ed --- include/sound/compress_driver.h | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h index 0732b4574674..10304fc4f719 100644 --- a/include/sound/compress_driver.h +++ b/include/sound/compress_driver.h @@ -168,18 +168,6 @@ int snd_compress_deregister(struct snd_compr *device); int snd_compress_new(struct snd_card *card, int device, int type, const char *id, struct snd_compr *compr); -/** - * snd_compr_use_pause_in_draining - Allow pause and resume in draining state - * @substream: compress substream to set - * - * Allow pause and resume in draining state. - * Only HW driver supports this transition can call this API. - */ -static inline void snd_compr_use_pause_in_draining(struct snd_compr_stream *substream) -{ - substream->device->use_pause_in_draining = true; -} - /* dsp driver callback apis * For playback: driver should call snd_compress_fragment_elapsed() to let the * framework know that a fragment has been consumed from the ring buffer From 8fd4291171807099c9c8992404ea90f3202959a7 Mon Sep 17 00:00:00 2001 From: Lynus Vaz Date: Wed, 20 Dec 2023 13:52:55 -0800 Subject: [PATCH 10/15] msm: kgsl: Do not release dma and anon buffers if unmap fails If iommu unmap fails and leaves dma or anon buffers still mapped in the iommu, do not free them. Change-Id: Ice0e1a59c1ac0ee7a9d62d8899966b84fa63d5ca Signed-off-by: Lynus Vaz Signed-off-by: Deepak Kumar (cherry picked from commit e7c4bb239ba84e45c05ccd1105d400f0a61a7613) --- drivers/gpu/msm/kgsl.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/drivers/gpu/msm/kgsl.c b/drivers/gpu/msm/kgsl.c index 964b8536666b..ff7e3e5468ea 100644 --- a/drivers/gpu/msm/kgsl.c +++ b/drivers/gpu/msm/kgsl.c @@ -344,6 +344,9 @@ static void kgsl_destroy_ion(struct kgsl_memdesc *memdesc) struct kgsl_mem_entry, memdesc); struct kgsl_dma_buf_meta *meta = entry->priv_data; + if (memdesc->priv & KGSL_MEMDESC_MAPPED) + return; + if (meta != NULL) { remove_dmabuf_list(meta); dma_buf_unmap_attachment(meta->attach, meta->table, @@ -367,6 +370,9 @@ static void kgsl_destroy_anon(struct kgsl_memdesc *memdesc) struct scatterlist *sg; struct page *page; + if (memdesc->priv & KGSL_MEMDESC_MAPPED) + return; + for_each_sg(memdesc->sgt->sgl, sg, memdesc->sgt->nents, i) { page = sg_page(sg); for (j = 0; j < (sg->length >> PAGE_SHIFT); j++) { From 5caba7258652fdc9ef541acba9a92d4723a6ba2f Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Tue, 16 Apr 2024 15:06:34 +0530 Subject: [PATCH 11/15] usb: gadget: f_cdev: Bail out from cer_resume if func_suspended Currently when the device exits from U3, all the interfaces will be resumed. In f_cdev driver, cser_resume will be called, which will clear is_suspended flag and process pending requests. Consider a situation where DUN interface is function suspended, and gadget resume happens eventually clearing is_suspended flag. Now if userspace writes something into at_usb node, f_cdev_write will queue the request without calling func_wakeup. And since the DUN interface is function suspended, host expects func_wakeup to be called before queueing the data. Fix this by bailing out from cser_resume() if function is already suspended, and wait for the userspace to issue remote-wakeup by writing something into at_usb node. Change-Id: Iba9c1dfd8a5deeb6c73af3ff370d51af193ff0e9 Signed-off-by: Prashanth K --- drivers/usb/gadget/function/f_cdev.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 1f9751d251de..0ba2dda270c7 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -554,12 +554,21 @@ static void usb_cser_start_rx(struct f_cdev *port); static void usb_cser_resume(struct usb_function *f) { struct f_cdev *port = func_to_port(f); + struct usb_composite_dev *cdev = f->config->cdev; unsigned long flags; int ret; struct usb_request *req, *t; struct usb_ep *in; + /* + * Bail out if the interface is in USB3 Function Suspend state. + * In that case resume is done by Function Resume request (write). + */ + if ((cdev->gadget->speed >= USB_SPEED_SUPER) && + port->func_is_suspended) + return; + pr_debug("%s\n", __func__); port->is_suspended = false; From d44f01f447c5cbd117ce5a13ccf993f995f0e7ef Mon Sep 17 00:00:00 2001 From: Prashanth K Date: Thu, 18 Apr 2024 12:20:22 +0530 Subject: [PATCH 12/15] usb: gadget: f_cdev: Call function wakeup if func_wakeup_pending is set Perform function wakeup from cser_resume if func_wakup_pending flag is true. Set it again if the func_wakeup returns -EAGAIN. Change-Id: If056327126e932911e3d832421b6171a50757e55 Signed-off-by: Prashanth K --- drivers/usb/gadget/function/f_cdev.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/drivers/usb/gadget/function/f_cdev.c b/drivers/usb/gadget/function/f_cdev.c index 0ba2dda270c7..50833c6e2c17 100644 --- a/drivers/usb/gadget/function/f_cdev.c +++ b/drivers/usb/gadget/function/f_cdev.c @@ -566,8 +566,13 @@ static void usb_cser_resume(struct usb_function *f) * In that case resume is done by Function Resume request (write). */ if ((cdev->gadget->speed >= USB_SPEED_SUPER) && - port->func_is_suspended) + port->func_is_suspended) { + if (port->func_wakeup_pending) { + ret = usb_func_wakeup(f); + port->func_wakeup_pending = (ret == -EAGAIN) ? true : false; + } return; + } pr_debug("%s\n", __func__); port->is_suspended = false; @@ -1462,9 +1467,10 @@ ssize_t f_cdev_write(struct file *file, spin_unlock_irqrestore(&port->port_lock, flags); if (gadget->speed >= USB_SPEED_SUPER - && port->func_is_suspended) + && port->func_is_suspended) { ret = usb_func_wakeup(func); - else + port->func_wakeup_pending = (ret == -EAGAIN) ? true : false; + } else ret = usb_gadget_wakeup(gadget); if (ret < 0 && ret != -EACCES && ret != -EAGAIN) { From 52f01d5092690f736803c47a2e139402dccda704 Mon Sep 17 00:00:00 2001 From: Sai Chaitanya Kaveti Date: Tue, 23 Jan 2024 16:50:41 +0530 Subject: [PATCH 13/15] msm: mhi_dev: Add UCI support if client req > TRE length Consider the following issue scenario: 1. Received client write request with size greater than single TRE element length. 2. mhi_dev_write() is called from UCI layer to handle the request. 3. In mhi_dev_write(), packet is split into multiple packets of TRE length and is expected to send as multiple packets of TRE length in loop. 4. The first transfer with TRE length is initiated and MHI received a completion call back as well. 5. As part of call back, UCI completion callback is called and the client buffer is cleared. 6. As remaining transfers are not completed, seeing NULL pointer dereference error while trying to process next transfers in the same write request. To handle this scenario from UCI layer, added the support to split the packets into TRE length if the request size is greater than TRE length. For this, saving and passing the minimum TRE size to UCI layer as part of channel doorbell processing. Change-Id: Id7468967e59effab690dacab6eca02d0f3f8ca2c Signed-off-by: Sai Chaitanya Kaveti --- drivers/platform/msm/mhi_dev/mhi.c | 29 +++---- drivers/platform/msm/mhi_dev/mhi_uci.c | 100 ++++++++++++++++++++----- 2 files changed, 98 insertions(+), 31 deletions(-) diff --git a/drivers/platform/msm/mhi_dev/mhi.c b/drivers/platform/msm/mhi_dev/mhi.c index 3720f4830682..68401a824bc2 100644 --- a/drivers/platform/msm/mhi_dev/mhi.c +++ b/drivers/platform/msm/mhi_dev/mhi.c @@ -2278,6 +2278,12 @@ static int mhi_dev_process_tre_ring(struct mhi_dev *mhi, ch = &mhi->ch[ring->id - mhi->ch_ring_start]; reason.ch_id = ch->ch_id; reason.reason = MHI_DEV_TRE_AVAILABLE; + /* + * Save lowest value of tre_len to split packets in UCI layer + * for write request of size more than tre_len. + */ + if (!ch->tre_size || ch->tre_size > el->tre.len) + ch->tre_size = el->tre.len; /* Invoke a callback to let the client know its data is ready. * Copy this event to the clients context so that it can be @@ -3466,7 +3472,7 @@ int mhi_dev_read_channel(struct mhi_req *mreq) uint64_t read_from_loc; ssize_t bytes_read = 0; size_t write_to_loc = 0; - uint32_t usr_buf_remaining; + uint32_t usr_buf_remaining, tre_size; int td_done = 0, rc = 0; struct mhi_dev_client *handle_client; @@ -3509,10 +3515,9 @@ int mhi_dev_read_channel(struct mhi_req *mreq) } el = &ring->ring_cache[ring->rd_offset]; - mhi_log(MHI_MSG_VERBOSE, "evtptr : 0x%llx\n", - el->tre.data_buf_ptr); - mhi_log(MHI_MSG_VERBOSE, "evntlen : 0x%x, offset:%lu\n", - el->tre.len, ring->rd_offset); + mhi_log(MHI_MSG_VERBOSE, + "TRE.PTR: 0x%llx, TRE.LEN: 0x%x, rd offset: %lu\n", + el->tre.data_buf_ptr, el->tre.len, ring->rd_offset); if (ch->tre_loc) { bytes_to_read = min(usr_buf_remaining, @@ -3531,17 +3536,15 @@ int mhi_dev_read_channel(struct mhi_req *mreq) ch->tre_loc = el->tre.data_buf_ptr; - ch->tre_size = el->tre.len; - ch->tre_bytes_left = ch->tre_size; - - mhi_log(MHI_MSG_VERBOSE, - "user_buf_remaining %d, ch->tre_size %d\n", - usr_buf_remaining, ch->tre_size); - bytes_to_read = min(usr_buf_remaining, ch->tre_size); + tre_size = el->tre.len; + ch->tre_bytes_left = el->tre.len; + mhi_log(MHI_MSG_VERBOSE, "user_buf_remaining %d, tre_size %d\n", + usr_buf_remaining, el->tre.len); + bytes_to_read = min(usr_buf_remaining, tre_size); } bytes_read += bytes_to_read; - addr_offset = ch->tre_size - ch->tre_bytes_left; + addr_offset = el->tre.len - ch->tre_bytes_left; read_from_loc = ch->tre_loc + addr_offset; write_to_loc = (size_t) mreq->buf + (mreq->len - usr_buf_remaining); diff --git a/drivers/platform/msm/mhi_dev/mhi_uci.c b/drivers/platform/msm/mhi_dev/mhi_uci.c index 8aca45f6957c..5862dd0a9fde 100644 --- a/drivers/platform/msm/mhi_dev/mhi_uci.c +++ b/drivers/platform/msm/mhi_dev/mhi_uci.c @@ -391,6 +391,7 @@ struct uci_client { int (*read)(struct uci_client *h, int *bytes); unsigned int tiocm; unsigned int at_ctrl_mask; + int tre_len; }; struct mhi_uci_ctxt_t { @@ -1466,8 +1467,9 @@ static ssize_t mhi_uci_client_write(struct file *file, { struct uci_client *uci_handle = NULL; void *data_loc; + const char __user *cur_buf; unsigned long memcpy_result; - int rc; + int rc = 0, tre_len, cur_rc = 0, count_left, cur_txfr_len; if (!file || !buf || !count || !file->private_data) { uci_log(UCI_DBG_DBG, "Invalid access to write\n"); @@ -1475,6 +1477,8 @@ static ssize_t mhi_uci_client_write(struct file *file, } uci_handle = file->private_data; + tre_len = uci_handle->tre_len; + if (!uci_handle->send || !uci_handle->out_handle) { uci_log(UCI_DBG_DBG, "Invalid handle or send\n"); return -EINVAL; @@ -1497,17 +1501,47 @@ static ssize_t mhi_uci_client_write(struct file *file, count, uci_handle->out_chan_attr->max_packet_size); } - data_loc = kmalloc(count, GFP_KERNEL); - if (!data_loc) - return -ENOMEM; + cur_txfr_len = count; - memcpy_result = copy_from_user(data_loc, buf, count); - if (memcpy_result) { - rc = -EFAULT; - goto error_memcpy; + if (!tre_len) + uci_log(UCI_DBG_ERROR, "tre_len is 0, not updated yet\n"); + else if (count > tre_len) { + uci_log(UCI_DBG_DBG, "Write req size (%d) > tre_len (%d)\n", count, tre_len); + cur_txfr_len = tre_len; } - rc = mhi_uci_send_packet(uci_handle, data_loc, count); + count_left = count; + cur_buf = buf; + + do { + data_loc = kmalloc(cur_txfr_len, GFP_KERNEL); + if (!data_loc) { + uci_log(UCI_DBG_ERROR, "Memory allocation failed\n"); + return -ENOMEM; + } + + memcpy_result = copy_from_user(data_loc, cur_buf, cur_txfr_len); + if (memcpy_result) { + uci_log(UCI_DBG_ERROR, "Mem copy failed\n"); + rc = -EFAULT; + goto error_memcpy; + } + + cur_rc = mhi_uci_send_packet(uci_handle, data_loc, cur_txfr_len); + if (cur_rc != cur_txfr_len) { + uci_log(UCI_DBG_ERROR, + "Send failed with error %d, after sending %d data\n", + cur_rc, rc); + rc = cur_rc; + goto error_memcpy; + } + rc += cur_rc; + cur_buf += cur_txfr_len; + count_left -= cur_txfr_len; + + if (count_left < tre_len) + cur_txfr_len = count_left; + } while (count_left); if (rc == count) return rc; @@ -1523,7 +1557,7 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, struct uci_client *uci_handle = NULL; void *data_loc; unsigned long memcpy_result; - int rc; + int rc = 0, tre_len, cur_rc = 0, count_left, cur_txfr_len; struct file *file = iocb->ki_filp; ssize_t count = iov_iter_count(buf); @@ -1533,6 +1567,8 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, } uci_handle = file->private_data; + tre_len = uci_handle->tre_len; + if (!uci_handle->send || !uci_handle->out_handle) { uci_log(UCI_DBG_DBG, "Invalid handle or send\n"); return -EINVAL; @@ -1555,17 +1591,44 @@ static ssize_t mhi_uci_client_write_iter(struct kiocb *iocb, count, uci_handle->out_chan_attr->max_packet_size); } - data_loc = kmalloc(count, GFP_KERNEL); - if (!data_loc) - return -ENOMEM; + cur_txfr_len = count; - memcpy_result = copy_from_iter_full(data_loc, count, buf); - if (!memcpy_result) { - rc = -EFAULT; - goto error_memcpy; + if (!tre_len) + uci_log(UCI_DBG_ERROR, "tre_len is 0, not updated yet\n"); + else if (count > tre_len) { + uci_log(UCI_DBG_DBG, "Write req size (%d) > tre_len (%d)\n", count, tre_len); + cur_txfr_len = tre_len; } - rc = mhi_uci_send_packet(uci_handle, data_loc, count); + count_left = count; + + do { + data_loc = kmalloc(cur_txfr_len, GFP_KERNEL); + if (!data_loc) { + uci_log(UCI_DBG_ERROR, "Memory allocation failed\n"); + return -ENOMEM; + } + + memcpy_result = copy_from_iter_full(data_loc, cur_txfr_len, buf); + if (!memcpy_result) { + uci_log(UCI_DBG_ERROR, "Mem copy failed\n"); + rc = -EFAULT; + goto error_memcpy; + } + cur_rc = mhi_uci_send_packet(uci_handle, data_loc, cur_txfr_len); + if (cur_rc != cur_txfr_len) { + uci_log(UCI_DBG_ERROR, + "Send failed with error %d, after sending %d data\n", + cur_rc, rc); + rc = cur_rc; + goto error_memcpy; + } + rc += cur_rc; + count_left -= cur_txfr_len; + if (count_left < tre_len) + cur_txfr_len = count_left; + } while (count_left); + if (rc == count) return rc; @@ -1683,6 +1746,7 @@ static void uci_event_notifier(struct mhi_dev_client_cb_reason *reason) uci_handle->in_chan); if (reason->ch_id % 2) { atomic_set(&uci_handle->write_data_ready, 1); + uci_handle->tre_len = uci_handle->out_handle->channel->tre_size; wake_up(&uci_handle->write_wq); } else { atomic_set(&uci_handle->read_data_ready, 1); From 4dcf58f7b4d423c9c6376e0b7b62bb03f229f73d Mon Sep 17 00:00:00 2001 From: Dheeraj Kumar Date: Thu, 2 May 2024 11:09:26 +0530 Subject: [PATCH 14/15] sdxnightJar.config: kernel changes for TRIGGER target As a part of port trigger FR, the iptables rule needs to be added, and the target TRIGGER should be enabled. Change-Id: I32cf6bf3fd5fc6dcc7844992b026648f908495ba Signed-off-by: Dheeraj Kumar --- arch/arm/configs/vendor/sdxnightjar.config | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/arm/configs/vendor/sdxnightjar.config b/arch/arm/configs/vendor/sdxnightjar.config index 86a9b16bd507..0772a299bf85 100644 --- a/arch/arm/configs/vendor/sdxnightjar.config +++ b/arch/arm/configs/vendor/sdxnightjar.config @@ -66,6 +66,7 @@ CONFIG_INTERCONNECT_QCOM=y CONFIG_DEBUG_FS=y CONFIG_ARCH_SDXNIGHTJAR=y CONFIG_ETHERNET=y +CONFIG_IP_NF_TARGET_TRIGGER_MODULE=y # CONFIG_NET_VENDOR_3COM is not set # CONFIG_NET_VENDOR_ADAPTEC is not set # CONFIG_NET_VENDOR_AGERE is not set From e9218e2bb19a137fba36fe65f85429c1dcd3a8f7 Mon Sep 17 00:00:00 2001 From: Santosh Sakore Date: Mon, 27 May 2024 14:29:54 +0530 Subject: [PATCH 15/15] msm: adsprpc: use-after-free (UAF) in global maps Currently, remote heap maps get added to the global list before the fastrpc_internal_mmap function completes the mapping. Meanwhile, the fastrpc_internal_munmap function accesses the map, starts unmapping, and frees the map before the fastrpc_internal_mmap function completes, resulting in a use-after-free (UAF) issue. Add the map to the list after the fastrpc_internal_mmap function completes the mapping. Change-Id: Ia524f142edba57a1f389dd0e5c83a1967c7f5a59 Acked-by: Abhishek Singh Signed-off-by: Santosh Sakore (cherry picked from commit 6f9f631c909b217b1510e1b385ce341a08061d6e) --- drivers/char/adsprpc.c | 92 ++++++++++++++++++++---------------------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/drivers/char/adsprpc.c b/drivers/char/adsprpc.c index 8e7b4eff7325..236a22608547 100644 --- a/drivers/char/adsprpc.c +++ b/drivers/char/adsprpc.c @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2012-2021, The Linux Foundation. All rights reserved. - * Copyright (c) 2022-2023, Qualcomm Innovation Center, Inc. All rights reserved. + * Copyright (c) 2022-2024 Qualcomm Innovation Center, Inc. All rights reserved. */ /* Uncomment this block to log an error on every VERIFY failure */ @@ -1108,64 +1108,43 @@ static void fastrpc_remote_buf_list_free(struct fastrpc_file *fl) } while (free); } +static void fastrpc_mmap_add_global(struct fastrpc_mmap *map) +{ + struct fastrpc_apps *me = &gfa; + unsigned long irq_flags = 0; + + spin_lock_irqsave(&me->hlock, irq_flags); + hlist_add_head(&map->hn, &me->maps); + spin_unlock_irqrestore(&me->hlock, irq_flags); +} + static void fastrpc_mmap_add(struct fastrpc_mmap *map) { - if (map->flags == ADSP_MMAP_HEAP_ADDR || - map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - struct fastrpc_apps *me = &gfa; + struct fastrpc_file *fl = map->fl; - spin_lock(&me->hlock); - hlist_add_head(&map->hn, &me->maps); - spin_unlock(&me->hlock); - } else { - struct fastrpc_file *fl = map->fl; - - hlist_add_head(&map->hn, &fl->maps); - } + hlist_add_head(&map->hn, &fl->maps); } static int fastrpc_mmap_find(struct fastrpc_file *fl, int fd, uintptr_t va, size_t len, int mflags, int refs, struct fastrpc_mmap **ppmap) { - struct fastrpc_apps *me = &gfa; struct fastrpc_mmap *match = NULL, *map = NULL; struct hlist_node *n; if ((va + len) < va) return -EFAULT; - if (mflags == ADSP_MMAP_HEAP_ADDR || - mflags == ADSP_MMAP_REMOTE_HEAP_ADDR) { - spin_lock(&me->hlock); - hlist_for_each_entry_safe(map, n, &me->maps, hn) { - if (va >= map->va && - va + len <= map->va + map->len && - map->fd == fd) { - if (refs) { - if (map->refs + 1 == INT_MAX) { - spin_unlock(&me->hlock); - return -ETOOMANYREFS; - } - map->refs++; - } - match = map; - break; - } - } - spin_unlock(&me->hlock); - } else { - hlist_for_each_entry_safe(map, n, &fl->maps, hn) { - if (va >= map->va && - va + len <= map->va + map->len && - map->fd == fd) { - if (refs) { - if (map->refs + 1 == INT_MAX) - return -ETOOMANYREFS; - map->refs++; - } - match = map; - break; + hlist_for_each_entry_safe(map, n, &fl->maps, hn) { + if (va >= map->va && + va + len <= map->va + map->len && + map->fd == fd) { + if (refs) { + if (map->refs + 1 == INT_MAX) + return -ETOOMANYREFS; + map->refs++; } + match = map; + break; } } if (match) { @@ -1641,7 +1620,9 @@ static int fastrpc_mmap_create(struct fastrpc_file *fl, int fd, } map->len = len; - fastrpc_mmap_add(map); + if ((mflags != ADSP_MMAP_HEAP_ADDR) && + (mflags != ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add(map); *ppmap = map; bail: @@ -4039,6 +4020,7 @@ static int fastrpc_init_create_static_process(struct fastrpc_file *fl, spin_lock(&me->hlock); mem->in_use = true; spin_unlock(&me->hlock); + fastrpc_mmap_add_global(mem); } phys = mem->phys; size = mem->size; @@ -4772,7 +4754,7 @@ static int fastrpc_mmap_remove_ssr(struct fastrpc_file *fl) me->enable_ramdump = false; bail: if (err && match) - fastrpc_mmap_add(match); + fastrpc_mmap_add_global(match); return err; } @@ -4901,7 +4883,11 @@ static int fastrpc_internal_munmap(struct fastrpc_file *fl, bail: if (err && map) { mutex_lock(&fl->map_mutex); - fastrpc_mmap_add(map); + if ((map->flags == ADSP_MMAP_HEAP_ADDR) || + (map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add_global(map); + else + fastrpc_mmap_add(map); mutex_unlock(&fl->map_mutex); } mutex_unlock(&fl->internal_map_mutex); @@ -4987,6 +4973,9 @@ static int fastrpc_internal_mem_map(struct fastrpc_file *fl, if (err) goto bail; ud->m.vaddrout = map->raddr; + if (ud->m.flags == ADSP_MMAP_HEAP_ADDR || + ud->m.flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + fastrpc_mmap_add_global(map); bail: if (err) { pr_err("adsprpc: %s failed to map fd %d flags %d err %d\n", @@ -5047,7 +5036,11 @@ bail: /* Add back to map list in case of error to unmap on DSP */ if (map) { mutex_lock(&fl->map_mutex); - fastrpc_mmap_add(map); + if ((map->flags == ADSP_MMAP_HEAP_ADDR) || + (map->flags == ADSP_MMAP_REMOTE_HEAP_ADDR)) + fastrpc_mmap_add_global(map); + else + fastrpc_mmap_add(map); mutex_unlock(&fl->map_mutex); } } @@ -5115,6 +5108,9 @@ static int fastrpc_internal_mmap(struct fastrpc_file *fl, if (err) goto bail; map->raddr = raddr; + if (ud->flags == ADSP_MMAP_HEAP_ADDR || + ud->flags == ADSP_MMAP_REMOTE_HEAP_ADDR) + fastrpc_mmap_add_global(map); } ud->vaddrout = raddr; bail: