Merge android13-5.15 into android13-5.15-lts

This merges the android13-5.15 branch into the -lts branch, catching
it up with the latest changes in there.

It contains the following commits:

* f7dbe96d1c39 Merge tag 'android13-5.15.182_r00' into android13-5.15
* 70ff3b45ba88 ANDROID: binder: fix minimum node priority comparison
* c128f36c63bd UPSTREAM: PCI/ASPM: Fix L1SS saving
* bfdd4619d735 UPSTREAM: PCI/ASPM: Save parent L1SS config in pci_save_aspm_l1ss_state()
* daab5d890e9f ANDROID: 16K: Remove ELF padding entry from map_file ranges
* 0caacc39200e ANDROID: ABI: Add to QCOM symbols list
* edfaa2dd3fcb UPSTREAM: binder: fix potential UAF of target_{proc,thread}
* b9a389cabebd ANDROID: GKI: Enable CONFIG_MEMFD_ASHMEM_SHIM
* 74fde7206b97 ANDROID: mm: shmem: Use memfd-ashmem-shim ioctl handler
* 46cd1ff96ae1 ANDROID: mm/memfd-ashmem-shim: Introduce shim layer

Change-Id: I8b4c8f7562a07af98936e80ea88ef8a4a7216a77
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
diff --git a/android/abi_gki_aarch64_qcom b/android/abi_gki_aarch64_qcom
index 9af3d1d..ddadbb3 100644
--- a/android/abi_gki_aarch64_qcom
+++ b/android/abi_gki_aarch64_qcom
@@ -116,6 +116,7 @@
   blk_mq_init_queue
   blk_mq_map_queues
   blk_mq_pci_map_queues
+  blk_mq_quiesce_queue_nowait
   blk_mq_requeue_request
   blk_mq_rq_cpu
   blk_mq_tagset_busy_iter
diff --git a/arch/arm64/configs/gki_defconfig b/arch/arm64/configs/gki_defconfig
index ea8e961..518fa258 100644
--- a/arch/arm64/configs/gki_defconfig
+++ b/arch/arm64/configs/gki_defconfig
@@ -127,6 +127,7 @@
 # CONFIG_ZONE_DMA is not set
 CONFIG_ANON_VMA_NAME=y
 CONFIG_LRU_GEN=y
+CONFIG_MEMFD_ASHMEM_SHIM=y
 CONFIG_DAMON=y
 CONFIG_DAMON_PADDR=y
 CONFIG_DAMON_RECLAIM=y
diff --git a/arch/x86/configs/gki_defconfig b/arch/x86/configs/gki_defconfig
index 7601911..9201883 100644
--- a/arch/x86/configs/gki_defconfig
+++ b/arch/x86/configs/gki_defconfig
@@ -116,6 +116,7 @@
 # CONFIG_ZONE_DMA is not set
 CONFIG_ANON_VMA_NAME=y
 CONFIG_LRU_GEN=y
+CONFIG_MEMFD_ASHMEM_SHIM=y
 CONFIG_DAMON=y
 CONFIG_DAMON_PADDR=y
 CONFIG_DAMON_RECLAIM=y
diff --git a/drivers/android/binder.c b/drivers/android/binder.c
index b06c14a..ccaa9f2 100644
--- a/drivers/android/binder.c
+++ b/drivers/android/binder.c
@@ -815,8 +815,8 @@ static void binder_transaction_priority(struct binder_thread *thread,
 		desired.sched_policy = SCHED_NORMAL;
 	}
 
-	if (node_prio.prio < t->priority.prio ||
-	    (node_prio.prio == t->priority.prio &&
+	if (node_prio.prio < desired.prio ||
+	    (node_prio.prio == desired.prio &&
 	     node_prio.sched_policy == SCHED_FIFO)) {
 		/*
 		 * In case the minimum priority on the node is
@@ -3842,10 +3842,6 @@ static void binder_transaction(struct binder_proc *proc,
 err_empty_call_stack:
 err_dead_binder:
 err_invalid_target_handle:
-	if (target_thread)
-		binder_thread_dec_tmpref(target_thread);
-	if (target_proc)
-		binder_proc_dec_tmpref(target_proc);
 	if (target_node) {
 		binder_dec_node(target_node, 1, 0);
 		binder_dec_node_tmpref(target_node);
@@ -3861,6 +3857,11 @@ static void binder_transaction(struct binder_proc *proc,
 		     tr->code, (u64)tr->data_size, (u64)tr->offsets_size,
 		     return_error_line);
 
+	if (target_thread)
+		binder_thread_dec_tmpref(target_thread);
+	if (target_proc)
+		binder_proc_dec_tmpref(target_proc);
+
 	{
 		struct binder_transaction_log_entry *fe;
 
diff --git a/drivers/pci/pcie/aspm.c b/drivers/pci/pcie/aspm.c
index 949cc54..798a71f 100644
--- a/drivers/pci/pcie/aspm.c
+++ b/drivers/pci/pcie/aspm.c
@@ -75,24 +75,44 @@ void pci_configure_aspm_l1ss(struct pci_dev *pdev)
 
 void pci_save_aspm_l1ss_state(struct pci_dev *pdev)
 {
+	struct pci_dev *parent = pdev->bus->self;
 	struct pci_cap_saved_state *save_state;
-	u16 l1ss = pdev->l1ss;
 	u32 *cap;
 
 	/*
+	 * If this is a Downstream Port, we never restore the L1SS state
+	 * directly; we only restore it when we restore the state of the
+	 * Upstream Port below it.
+	 */
+	if (pcie_downstream_port(pdev) || !parent)
+		return;
+
+	if (!pdev->l1ss || !parent->l1ss)
+		return;
+
+	/*
 	 * Save L1 substate configuration. The ASPM L0s/L1 configuration
 	 * in PCI_EXP_LNKCTL_ASPMC is saved by pci_save_pcie_state().
 	 */
-	if (!l1ss)
-		return;
-
 	save_state = pci_find_saved_ext_cap(pdev, PCI_EXT_CAP_ID_L1SS);
 	if (!save_state)
 		return;
 
 	cap = &save_state->cap.data[0];
-	pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL2, cap++);
-	pci_read_config_dword(pdev, l1ss + PCI_L1SS_CTL1, cap++);
+	pci_read_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL2, cap++);
+	pci_read_config_dword(pdev, pdev->l1ss + PCI_L1SS_CTL1, cap++);
+
+	/*
+	 * Save parent's L1 substate configuration so we have it for
+	 * pci_restore_aspm_l1ss_state(pdev) to restore.
+	 */
+	save_state = pci_find_saved_ext_cap(parent, PCI_EXT_CAP_ID_L1SS);
+	if (!save_state)
+		return;
+
+	cap = &save_state->cap.data[0];
+	pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL2, cap++);
+	pci_read_config_dword(parent, parent->l1ss + PCI_L1SS_CTL1, cap++);
 }
 
 static void pci_clear_and_set_dword(struct pci_dev *pdev, int pos,
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 211e330..7624ae2 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -65,6 +65,7 @@
 #include <linux/namei.h>
 #include <linux/mnt_namespace.h>
 #include <linux/mm.h>
+#include <linux/pgsize_migration.h>
 #include <linux/swap.h>
 #include <linux/rcupdate.h>
 #include <linux/kallsyms.h>
@@ -2462,7 +2463,7 @@ proc_map_files_readdir(struct file *file, struct dir_context *ctx)
 		}
 
 		p->start = vma->vm_start;
-		p->end = vma->vm_end;
+		p->end = VMA_PAD_START(vma);
 		p->mode = vma->vm_file->f_mode;
 	}
 	mmap_read_unlock(mm);
diff --git a/mm/Kconfig b/mm/Kconfig
index ae181c7..9d982e5 100644
--- a/mm/Kconfig
+++ b/mm/Kconfig
@@ -942,6 +942,17 @@
 	  This option has a per-memcg and per-node memory overhead.
 # }
 
+config MEMFD_ASHMEM_SHIM
+	bool "Memfd ashmem ioctl compatibility support"
+	depends on MEMFD_CREATE
+	help
+	  This provides compatibility support for ashmem ioctl commands against
+	  memfd file descriptors. This is useful for compatibility on Android
+	  for older applications that may use ashmem's ioctl commands on the
+	  now memfds passed to them.
+
+	  Unless you are running Android, say N.
+
 source "mm/damon/Kconfig"
 
 config ARCH_SUPPORTS_SPECULATIVE_PAGE_FAULT
diff --git a/mm/Makefile b/mm/Makefile
index a91fd8a..0d74b5a 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -125,6 +125,7 @@
 obj-$(CONFIG_ZONE_DEVICE) += memremap.o
 obj-$(CONFIG_HMM_MIRROR) += hmm.o
 obj-$(CONFIG_MEMFD_CREATE) += memfd.o
+obj-$(CONFIG_MEMFD_ASHMEM_SHIM) += memfd-ashmem-shim.o
 obj-$(CONFIG_MAPPING_DIRTY_HELPERS) += mapping_dirty_helpers.o
 obj-$(CONFIG_PTDUMP_CORE) += ptdump.o
 obj-$(CONFIG_PAGE_REPORTING) += page_reporting.o
diff --git a/mm/memfd-ashmem-shim-internal.h b/mm/memfd-ashmem-shim-internal.h
new file mode 100644
index 0000000..b499434
--- /dev/null
+++ b/mm/memfd-ashmem-shim-internal.h
@@ -0,0 +1,52 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Ashmem compatability for memfd
+ *
+ * Copyright (c) 2025, Google LLC.
+ * Author: Isaac J. Manjarres <isaacmanjarres@google.com>
+ */
+
+#ifndef _MM_MEMFD_ASHMEM_SHIM_INTERNAL_H
+#define _MM_MEMFD_ASHMEM_SHIM_INTERNAL_H
+
+#include <linux/compat.h>
+#include <linux/ioctl.h>
+#include <linux/types.h>
+
+#define ASHMEM_NAME_LEN		256
+
+/* Return values from ASHMEM_PIN: Was the mapping purged while unpinned? */
+#define ASHMEM_NOT_PURGED	0
+#define ASHMEM_WAS_PURGED	1
+
+/* Return values from ASHMEM_GET_PIN_STATUS: Is the mapping pinned? */
+#define ASHMEM_IS_UNPINNED	0
+#define ASHMEM_IS_PINNED	1
+
+struct ashmem_pin {
+	__u32 offset;	/* offset into region, in bytes, page-aligned */
+	__u32 len;	/* length forward from offset, in bytes, page-aligned */
+};
+
+#define __ASHMEMIOC		0x77
+
+#define ASHMEM_SET_NAME		_IOW(__ASHMEMIOC, 1, char[ASHMEM_NAME_LEN])
+#define ASHMEM_GET_NAME		_IOR(__ASHMEMIOC, 2, char[ASHMEM_NAME_LEN])
+#define ASHMEM_SET_SIZE		_IOW(__ASHMEMIOC, 3, size_t)
+#define ASHMEM_GET_SIZE		_IO(__ASHMEMIOC, 4)
+#define ASHMEM_SET_PROT_MASK	_IOW(__ASHMEMIOC, 5, unsigned long)
+#define ASHMEM_GET_PROT_MASK	_IO(__ASHMEMIOC, 6)
+#define ASHMEM_PIN		_IOW(__ASHMEMIOC, 7, struct ashmem_pin)
+#define ASHMEM_UNPIN		_IOW(__ASHMEMIOC, 8, struct ashmem_pin)
+#define ASHMEM_GET_PIN_STATUS	_IO(__ASHMEMIOC, 9)
+#define ASHMEM_PURGE_ALL_CACHES	_IO(__ASHMEMIOC, 10)
+#define ASHMEM_GET_FILE_ID		_IOR(__ASHMEMIOC, 11, unsigned long)
+
+/* support of 32bit userspace on 64bit platforms */
+#ifdef CONFIG_COMPAT
+#define COMPAT_ASHMEM_SET_SIZE		_IOW(__ASHMEMIOC, 3, compat_size_t)
+#define COMPAT_ASHMEM_SET_PROT_MASK	_IOW(__ASHMEMIOC, 5, unsigned int)
+#endif
+
+#endif /* _MM_MEMFD_ASHMEM_SHIM_INTERNAL_H */
diff --git a/mm/memfd-ashmem-shim.c b/mm/memfd-ashmem-shim.c
new file mode 100644
index 0000000..258498cc
--- /dev/null
+++ b/mm/memfd-ashmem-shim.c
@@ -0,0 +1,213 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Ashmem compatability for memfd
+ *
+ * Copyright (c) 2025, Google LLC.
+ * Author: Isaac J. Manjarres <isaacmanjarres@google.com>
+ */
+
+#include <asm-generic/mman-common.h>
+#include <linux/capability.h>
+#include <linux/fs.h>
+#include <linux/memfd.h>
+#include <linux/uaccess.h>
+
+#include "memfd-ashmem-shim.h"
+#include "memfd-ashmem-shim-internal.h"
+
+/* memfd file names all start with memfd: */
+#define MEMFD_PREFIX "memfd:"
+#define MEMFD_PREFIX_LEN (sizeof(MEMFD_PREFIX) - 1)
+
+static const char *get_memfd_name(struct file *file)
+{
+	/* This pointer is always valid, so no need to check if it's NULL. */
+	const char *file_name = file->f_path.dentry->d_name.name;
+
+	if (file_name != strstr(file_name, MEMFD_PREFIX))
+		return NULL;
+
+	return file_name;
+}
+
+static long get_name(struct file *file, void __user *name)
+{
+	const char *file_name = get_memfd_name(file);
+	size_t len;
+
+	if (!file_name)
+		return -EINVAL;
+
+	/* Strip MEMFD_PREFIX to retain compatibility with ashmem driver. */
+	file_name = &file_name[MEMFD_PREFIX_LEN];
+
+	/*
+	 * The expectation is that the user provided buffer is ASHMEM_NAME_LEN in size, which is
+	 * larger than the maximum size of a name for a memfd buffer, so the name should always fit
+	 * within the given buffer.
+	 *
+	 * However, we should ensure that the string will indeed fit in the user provided buffer.
+	 *
+	 * Add 1 to the copy size to account for the NUL terminator
+	 */
+	len = strlen(file_name) + 1;
+	if (len > ASHMEM_NAME_LEN)
+		return -EINVAL;
+
+	return copy_to_user(name, file_name, len) ? -EFAULT : 0;
+}
+
+static long get_prot_mask(struct file *file)
+{
+	long prot_mask = PROT_READ | PROT_EXEC;
+	long seals = memfd_fcntl(file, F_GET_SEALS, 0);
+
+	if (seals < 0)
+		return seals;
+
+	/* memfds are readable and executable by default. Only writability can be changed. */
+	if (!(seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE)))
+		prot_mask |= PROT_WRITE;
+
+	return prot_mask;
+}
+
+static long set_prot_mask(struct file *file, unsigned long prot)
+{
+	long curr_prot = get_prot_mask(file);
+	long ret = 0;
+
+	if (curr_prot < 0)
+		return curr_prot;
+
+	/*
+	 * memfds are always readable and executable; there is no way to remove either mapping
+	 * permission, nor is there a known usecase that requires it.
+	 *
+	 * Attempting to remove either of these mapping permissions will return successfully, but
+	 * will be a nop, as the buffer will still be mappable with these permissions.
+	 */
+	prot |= PROT_READ | PROT_EXEC;
+
+	/* Only allow permissions to be removed. */
+	if ((curr_prot & prot) != prot)
+		return -EINVAL;
+
+	/*
+	 * Removing PROT_WRITE:
+	 *
+	 * We could prevent any other mappings from having write permissions by adding the
+	 * F_SEAL_WRITE mapping. However, that would conflict with known usecases where it is
+	 * desirable to maintain an existing writable mapping, but forbid future writable mappings.
+	 *
+	 * To support those usecases, we use F_SEAL_FUTURE_WRITE.
+	 */
+	if (!(prot & PROT_WRITE))
+		ret = memfd_fcntl(file, F_ADD_SEALS, F_SEAL_FUTURE_WRITE);
+
+	return ret;
+}
+
+/*
+ * memfd_ashmem_shim_ioctl - ioctl handler for ashmem commands
+ * @file: The shmem file.
+ * @cmd: The ioctl command.
+ * @arg: The argument for the ioctl command.
+ *
+ * The purpose of this handler is to allow old applications to continue working
+ * on newer kernels by allowing them to invoke ashmem ioctl commands on memfds.
+ *
+ * The ioctl handler attempts to retain as much compatibility with the ashmem
+ * driver as possible.
+ */
+long memfd_ashmem_shim_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	long ret = -ENOTTY;
+	unsigned long inode_nr;
+
+	switch (cmd) {
+	/*
+	 * Older applications won't create memfds and try to use ASHMEM_SET_NAME/ASHMEM_SET_SIZE on
+	 * them intentionally.
+	 *
+	 * Instead, we can end up in this scenario if an old application receives a memfd that was
+	 * created by another process.
+	 *
+	 * However, the current process shouldn't expect to be able to reliably [re]name/size a
+	 * buffer that was shared with it, since the process that shared that buffer with it, or
+	 * any other process that references the buffer could have already mapped it.
+	 *
+	 * Additionally in the case of ASHMEM_SET_SIZE, when processes create memfds that are going
+	 * to be shared with other processes in Android, they also specify the size of the memory
+	 * region and seal the file against any size changes. Therefore, ASHMEM_SET_SIZE should not
+	 * be supported anyway.
+	 *
+	 * Therefore, it is reasonable to return -EINVAL here, as if the buffer was already mapped.
+	 */
+	case ASHMEM_SET_NAME:
+	case ASHMEM_SET_SIZE:
+		ret = -EINVAL;
+		break;
+	case ASHMEM_GET_NAME:
+		ret = get_name(file, (void __user *)arg);
+		break;
+	case ASHMEM_GET_SIZE:
+		ret = i_size_read(file_inode(file));
+		break;
+	case ASHMEM_SET_PROT_MASK:
+		ret = set_prot_mask(file, arg);
+		break;
+	case ASHMEM_GET_PROT_MASK:
+		ret = get_prot_mask(file);
+		break;
+	/*
+	 * Unpinning ashmem buffers was deprecated with the release of Android 10,
+	 * as it did not yield any remarkable benefits. Therefore, ignore pinning
+	 * related requests.
+	 *
+	 * This makes it so that memory is always "pinned" or never entirely freed
+	 * until all references to the ashmem buffer are dropped. The memory occupied
+	 * by the buffer is still subject to being reclaimed (swapped out) under memory
+	 * pressure, but that is not the same as being freed.
+	 *
+	 * This makes it so that:
+	 *
+	 * 1. Memory is always pinned and therefore never purged.
+	 * 2. Requests to unpin memory (make it a candidate for being freed) are ignored.
+	 */
+	case ASHMEM_PIN:
+		ret = ASHMEM_NOT_PURGED;
+		break;
+	case ASHMEM_UNPIN:
+		ret = 0;
+		break;
+	case ASHMEM_GET_PIN_STATUS:
+		ret = ASHMEM_IS_PINNED;
+		break;
+	case ASHMEM_PURGE_ALL_CACHES:
+		ret = capable(CAP_SYS_ADMIN) ? 0 : -EPERM;
+		break;
+	case ASHMEM_GET_FILE_ID:
+		inode_nr = file_inode(file)->i_ino;
+		if (copy_to_user((void __user *)arg, &inode_nr, sizeof(inode_nr)))
+			ret = -EFAULT;
+		else
+			ret = 0;
+		break;
+	}
+
+	return ret;
+}
+
+#ifdef CONFIG_COMPAT
+long memfd_ashmem_shim_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+	if (cmd == COMPAT_ASHMEM_SET_SIZE)
+		cmd = ASHMEM_SET_SIZE;
+	else if (cmd == COMPAT_ASHMEM_SET_PROT_MASK)
+		cmd = ASHMEM_SET_PROT_MASK;
+
+	return memfd_ashmem_shim_ioctl(file, cmd, arg);
+}
+#endif
diff --git a/mm/memfd-ashmem-shim.h b/mm/memfd-ashmem-shim.h
new file mode 100644
index 0000000..026789b0
--- /dev/null
+++ b/mm/memfd-ashmem-shim.h
@@ -0,0 +1,21 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef __MM_MEMFD_ASHMEM_SHIM_H
+#define __MM_MEMFD_ASHMEM_SHIM_H
+
+/*
+ * mm/memfd-ashmem-shim.h
+ *
+ * Ashmem compatability for memfd
+ *
+ * Copyright (c) 2025, Google LLC.
+ * Author: Isaac J. Manjarres <isaacmanjarres@google.com>
+ *
+ */
+
+#include <linux/fs.h>
+
+long memfd_ashmem_shim_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#ifdef CONFIG_COMPAT
+long memfd_ashmem_shim_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
+#endif
+#endif /* __MM_MEMFD_ASHMEM_SHIM_H */
diff --git a/mm/shmem.c b/mm/shmem.c
index 7eada4d..23fc50a 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -85,6 +85,10 @@ static struct vfsmount *shm_mnt;
 
 #include "internal.h"
 
+#ifdef CONFIG_MEMFD_ASHMEM_SHIM
+#include "memfd-ashmem-shim.h"
+#endif
+
 #define BLOCKS_PER_PAGE  (PAGE_SIZE/512)
 #define VM_ACCT(size)    (PAGE_ALIGN(size) >> PAGE_SHIFT)
 
@@ -3858,6 +3862,12 @@ static const struct file_operations shmem_file_operations = {
 	.splice_write	= iter_file_splice_write,
 	.fallocate	= shmem_fallocate,
 #endif
+#ifdef CONFIG_MEMFD_ASHMEM_SHIM
+	.unlocked_ioctl	= memfd_ashmem_shim_ioctl,
+#ifdef CONFIG_COMPAT
+	.compat_ioctl	= memfd_ashmem_shim_compat_ioctl,
+#endif
+#endif
 };
 
 static const struct inode_operations shmem_inode_operations = {