From: Greg Kroah-Hartman Date: Sun, 7 Jun 2026 07:41:06 +0000 (+0200) Subject: 6.12-stable patches X-Git-Url: http://git.ipfire.org/gitweb/index.cgi?a=commitdiff_plain;ds=inline;p=thirdparty%2Fkernel%2Fstable-queue.git 6.12-stable patches added patches: hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch memfd-deny-writeable-mappings-when-implying-seal_write.patch mm-memfd-fix-spelling-and-grammatical-issues.patch mm-perform-all-memfd-seal-checks-in-a-single-place.patch --- diff --git a/queue-6.12/hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch b/queue-6.12/hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch new file mode 100644 index 0000000000..bf4443a272 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch @@ -0,0 +1,140 @@ +From stable+bounces-259653-greg=kroah.com@vger.kernel.org Mon Jun 1 21:59:44 2026 +From: Sasha Levin +Date: Mon, 1 Jun 2026 15:59:14 -0400 +Subject: hwmon: (pmbus/adm1266) serialize GPIO PMBus accesses with pmbus_lock +To: stable@vger.kernel.org +Cc: Abdurrahman Hussain , Bartosz Golaszewski , Guenter Roeck , Sasha Levin +Message-ID: <20260601195914.1214650-1-sashal@kernel.org> + +From: Abdurrahman Hussain + +[ Upstream commit bab8c6fb5af8df7e753d196c1262cb78e92ca872 ] + +adm1266_gpio_get(), adm1266_gpio_get_multiple(), and +adm1266_gpio_dbg_show() all issue PMBus reads against the device but +none of them take pmbus_lock. The pmbus_core framework holds +pmbus_lock around its own multi-transaction sequences (notably the +"set PAGE, then read paged register" pattern used by hwmon +attributes), so an unlocked GPIO accessor can land between a PAGE +write and the subsequent paged read in another thread and corrupt +either side's view of the device state machine. + +Take pmbus_lock at the top of each of the three accessors via the +scope-based guard(). The lock is uncontended in the common case and +adds only a single mutex round-trip per call. + +Fixes: d98dfad35c38 ("hwmon: (pmbus/adm1266) Add support for GPIOs") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Reviewed-by: Bartosz Golaszewski +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-6-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +[ open-coded each `guard(pmbus_lock)(data->client)` as explicit `pmbus_lock_interruptible()`/`pmbus_unlock()` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 40 ++++++++++++++++++++++++++++++++++------ + 1 file changed, 34 insertions(+), 6 deletions(-) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -173,7 +173,12 @@ static int adm1266_gpio_get(struct gpio_ + else + pmbus_cmd = ADM1266_PDIO_STATUS; + ++ ret = pmbus_lock_interruptible(data->client); ++ if (ret) ++ return ret; ++ + ret = i2c_smbus_read_block_data(data->client, pmbus_cmd, read_buf); ++ pmbus_unlock(data->client); + if (ret < 0) + return ret; + if (ret < 2) +@@ -195,11 +200,19 @@ static int adm1266_gpio_get_multiple(str + unsigned int gpio_nr; + int ret; + ++ ret = pmbus_lock_interruptible(data->client); ++ if (ret) ++ return ret; ++ + ret = i2c_smbus_read_block_data(data->client, ADM1266_GPIO_STATUS, read_buf); +- if (ret < 0) ++ if (ret < 0) { ++ pmbus_unlock(data->client); + return ret; +- if (ret < 2) ++ } ++ if (ret < 2) { ++ pmbus_unlock(data->client); + return -EIO; ++ } + + status = read_buf[0] + (read_buf[1] << 8); + +@@ -210,10 +223,14 @@ static int adm1266_gpio_get_multiple(str + } + + ret = i2c_smbus_read_block_data(data->client, ADM1266_PDIO_STATUS, read_buf); +- if (ret < 0) ++ if (ret < 0) { ++ pmbus_unlock(data->client); + return ret; +- if (ret < 2) ++ } ++ if (ret < 2) { ++ pmbus_unlock(data->client); + return -EIO; ++ } + + status = read_buf[0] + (read_buf[1] << 8); + +@@ -222,6 +239,8 @@ static int adm1266_gpio_get_multiple(str + set_bit(gpio_nr, bits); + } + ++ pmbus_unlock(data->client); ++ + return 0; + } + +@@ -236,11 +255,16 @@ static void adm1266_gpio_dbg_show(struct + int ret; + int i; + ++ if (pmbus_lock_interruptible(data->client)) ++ return; ++ + for (i = 0; i < ADM1266_GPIO_NR; i++) { + write_cmd = adm1266_gpio_mapping[i][1]; + ret = adm1266_pmbus_block_xfer(data, ADM1266_GPIO_CONFIG, 1, &write_cmd, read_buf); +- if (ret != 2) ++ if (ret != 2) { ++ pmbus_unlock(data->client); + return; ++ } + + gpio_config = read_buf[0]; + seq_puts(s, adm1266_names[i]); +@@ -262,8 +286,10 @@ static void adm1266_gpio_dbg_show(struct + + write_cmd = 0xFF; + ret = adm1266_pmbus_block_xfer(data, ADM1266_PDIO_CONFIG, 1, &write_cmd, read_buf); +- if (ret != 32) ++ if (ret != 32) { ++ pmbus_unlock(data->client); + return; ++ } + + for (i = 0; i < ADM1266_PDIO_NR; i++) { + seq_puts(s, adm1266_names[ADM1266_GPIO_NR + i]); +@@ -286,6 +312,8 @@ static void adm1266_gpio_dbg_show(struct + + seq_puts(s, ")\n"); + } ++ ++ pmbus_unlock(data->client); + } + + static int adm1266_config_gpio(struct adm1266_data *data) diff --git a/queue-6.12/hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch b/queue-6.12/hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch new file mode 100644 index 0000000000..41d0311365 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch @@ -0,0 +1,80 @@ +From stable+bounces-259619-greg=kroah.com@vger.kernel.org Mon Jun 1 18:39:56 2026 +From: Sasha Levin +Date: Mon, 1 Jun 2026 12:28:40 -0400 +Subject: hwmon: (pmbus/adm1266) serialize NVMEM blackbox read with pmbus_lock +To: stable@vger.kernel.org +Cc: Abdurrahman Hussain , Guenter Roeck , Sasha Levin +Message-ID: <20260601162840.975891-1-sashal@kernel.org> + +From: Abdurrahman Hussain + +[ Upstream commit 9f1dd8f9491eb840cbea7ffdf4cad031e25f8ae0 ] + +adm1266_nvmem_read() is the reg_read callback the NVMEM core invokes +when userspace reads /sys/bus/nvmem/devices/.../nvmem on this chip. +On the first byte of every read it does a memset of data->dev_mem, +walks the device blackbox through adm1266_nvmem_read_blackbox() +(which issues a chain of PMBus block transactions), and then memcpys +the refreshed buffer out to userspace. None of that runs under +pmbus_lock today. + +Two consequences: + + - The PMBus traffic the refresh issues is not serialised against + pmbus_core's own multi-step PAGE+register sequences. A paged + hwmon attribute read from another thread can land between a + PAGE write and the paged read in either direction and corrupt + one side's view of the device state machine. + + - The NVMEM core does not serialise concurrent reg_read calls, so + two userspace readers racing at offset 0 can interleave the + memset of data->dev_mem with another reader's + adm1266_nvmem_read_blackbox() refill or memcpy out, returning + torn data to userspace. + +Take pmbus_lock at the top of adm1266_nvmem_read() via the +scope-based guard(). Patch 5 of this series moves +adm1266_config_nvmem() past pmbus_do_probe() so the lock is +guaranteed to be live before the callback is reachable from +userspace. + +Fixes: 15609d189302 ("hwmon: (pmbus/adm1266) read blackbox") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-7-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +[ changed `guard(pmbus_lock)(data->client)` to explicit `pmbus_lock_interruptible()`/`pmbus_unlock()` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 7 +++++++ + 1 file changed, 7 insertions(+) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -398,18 +398,25 @@ static int adm1266_nvmem_read(void *priv + if (offset + bytes > data->nvmem_config.size) + return -EINVAL; + ++ ret = pmbus_lock_interruptible(data->client); ++ if (ret) ++ return ret; ++ + if (offset == 0) { + memset(data->dev_mem, 0, data->nvmem_config.size); + + ret = adm1266_nvmem_read_blackbox(data, data->dev_mem); + if (ret) { + dev_err(&data->client->dev, "Could not read blackbox!"); ++ pmbus_unlock(data->client); + return ret; + } + } + + memcpy(val, data->dev_mem + offset, bytes); + ++ pmbus_unlock(data->client); ++ + return 0; + } + diff --git a/queue-6.12/hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch b/queue-6.12/hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch new file mode 100644 index 0000000000..f61e2b1ad6 --- /dev/null +++ b/queue-6.12/hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch @@ -0,0 +1,54 @@ +From stable+bounces-259583-greg=kroah.com@vger.kernel.org Mon Jun 1 16:51:58 2026 +From: Sasha Levin +Date: Mon, 1 Jun 2026 10:46:51 -0400 +Subject: hwmon: (pmbus/adm1266) serialize sequencer_state debugfs read with pmbus_lock +To: stable@vger.kernel.org +Cc: Abdurrahman Hussain , Guenter Roeck , Sasha Levin +Message-ID: <20260601144651.887662-1-sashal@kernel.org> + +From: Abdurrahman Hussain + +[ Upstream commit 4e4af55aaca7f6d7673d5f9889ad0529db86a048 ] + +adm1266_state_read() backs the sequencer_state debugfs entry and +issues an i2c_smbus_read_word_data(client, ADM1266_READ_STATE) +against the device without taking pmbus_lock. pmbus_core holds +pmbus_lock around its own multi-transaction sequences (notably the +"set PAGE, then read paged register" pattern used by hwmon +attributes), so an unlocked debugfs reader can land between a PAGE +write and the subsequent paged read in another thread. READ_STATE +itself is not paged, so it cannot corrupt PAGE in flight, but the +same defensive serialisation that applies to the GPIO accessors +applies here: any direct device access from outside pmbus_core +should be ordered with respect to pmbus_core's own. + +Take pmbus_lock at the top of adm1266_state_read() via the +scope-based guard(). + +Fixes: ed1ff457e187 ("hwmon: (pmbus/adm1266) add debugfs for states") +Cc: stable@vger.kernel.org +Signed-off-by: Abdurrahman Hussain +Link: https://lore.kernel.org/r/20260518-adm1266-gpio-fixes-v3-8-e425e4f88139@nexthop.ai +Signed-off-by: Guenter Roeck +[ replaced `guard(pmbus_lock)(client)` with manual `pmbus_lock_interruptible()`/`pmbus_unlock()` ] +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + drivers/hwmon/pmbus/adm1266.c | 5 +++++ + 1 file changed, 5 insertions(+) + +--- a/drivers/hwmon/pmbus/adm1266.c ++++ b/drivers/hwmon/pmbus/adm1266.c +@@ -328,7 +328,12 @@ static int adm1266_state_read(struct seq + struct i2c_client *client = to_i2c_client(dev); + int ret; + ++ ret = pmbus_lock_interruptible(client); ++ if (ret) ++ return ret; ++ + ret = i2c_smbus_read_word_data(client, ADM1266_READ_STATE); ++ pmbus_unlock(client); + if (ret < 0) + return ret; + diff --git a/queue-6.12/memfd-deny-writeable-mappings-when-implying-seal_write.patch b/queue-6.12/memfd-deny-writeable-mappings-when-implying-seal_write.patch new file mode 100644 index 0000000000..f4f47d4c92 --- /dev/null +++ b/queue-6.12/memfd-deny-writeable-mappings-when-implying-seal_write.patch @@ -0,0 +1,71 @@ +From stable+bounces-260503-greg=kroah.com@vger.kernel.org Thu Jun 4 16:15:57 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 09:54:21 -0400 +Subject: memfd: deny writeable mappings when implying SEAL_WRITE +To: stable@vger.kernel.org +Cc: "Pratyush Yadav (Google)" , Pasha Tatashin , Jeff Xu , Baolin Wang , Brendan Jackman , Greg Thelen , Hugh Dickins , Kees Cook , "David Hildenbrand (Arm)" , Andrew Morton , Sasha Levin +Message-ID: <20260604135421.3490773-3-sashal@kernel.org> + +From: "Pratyush Yadav (Google)" + +[ Upstream commit 3b041514cb6eae45869b020f743c14d983363222 ] + +When SEAL_EXEC is added, SEAL_WRITE is implied to make W^X. But the +implied seal is set after the check that makes sure the memfd can not have +any writable mappings. This means one can use SEAL_EXEC to apply +SEAL_WRITE while having writeable mappings. + +This breaks the contract that SEAL_WRITE provides and can be used by an +attacker to pass a memfd that appears to be write sealed but can still be +modified arbitrarily. + +Fix this by adding the implied seals before the call for +mapping_deny_writable() is done. + +Link: https://lore.kernel.org/20260505133922.797635-1-pratyush@kernel.org +Fixes: c4f75bc8bd6b ("mm/memfd: add write seals when apply SEAL_EXEC to executable memfd") +Signed-off-by: Pratyush Yadav (Google) +Reviewed-by: Pasha Tatashin +Acked-by: Jeff Xu +Cc: Baolin Wang +Cc: Brendan Jackman +Cc: Greg Thelen +Cc: Hugh Dickins +Cc: Kees Cook +Cc: "David Hildenbrand (Arm)" +Cc: +Signed-off-by: Andrew Morton +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/memfd.c | 12 ++++++------ + 1 file changed, 6 insertions(+), 6 deletions(-) + +--- a/mm/memfd.c ++++ b/mm/memfd.c +@@ -273,6 +273,12 @@ static int memfd_add_seals(struct file * + goto unlock; + } + ++ /* ++ * SEAL_EXEC implies SEAL_WRITE, making W^X from the start. ++ */ ++ if (seals & F_SEAL_EXEC && inode->i_mode & 0111) ++ seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; ++ + if ((seals & F_SEAL_WRITE) && !(*file_seals & F_SEAL_WRITE)) { + error = mapping_deny_writable(file->f_mapping); + if (error) +@@ -285,12 +291,6 @@ static int memfd_add_seals(struct file * + } + } + +- /* +- * SEAL_EXEC implies SEAL_WRITE, making W^X from the start. +- */ +- if (seals & F_SEAL_EXEC && inode->i_mode & 0111) +- seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; +- + *file_seals |= seals; + error = 0; + diff --git a/queue-6.12/mm-memfd-fix-spelling-and-grammatical-issues.patch b/queue-6.12/mm-memfd-fix-spelling-and-grammatical-issues.patch new file mode 100644 index 0000000000..999212f196 --- /dev/null +++ b/queue-6.12/mm-memfd-fix-spelling-and-grammatical-issues.patch @@ -0,0 +1,48 @@ +From stable+bounces-260502-greg=kroah.com@vger.kernel.org Thu Jun 4 16:15:53 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 09:54:20 -0400 +Subject: mm/memfd: fix spelling and grammatical issues +To: stable@vger.kernel.org +Cc: Liu Ye , Andrew Morton , Sasha Levin +Message-ID: <20260604135421.3490773-2-sashal@kernel.org> + +From: Liu Ye + +[ Upstream commit 33c9b01ed2fcbc101cdfeb497f4581e981e7c1e7 ] + +The comment "If a private mapping then writability is irrelevant" contains +a typo. It should be "If a private mapping then writability is +irrelevant". The comment "SEAL_EXEC implys SEAL_WRITE, making W^X from +the start." contains a typo. It should be "SEAL_EXEC implies SEAL_WRITE, +making W^X from the start." + +Link: https://lkml.kernel.org/r/20250206060958.98010-1-liuye@kylinos.cn +Signed-off-by: Liu Ye +Signed-off-by: Andrew Morton +Stable-dep-of: 3b041514cb6e ("memfd: deny writeable mappings when implying SEAL_WRITE") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + mm/memfd.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +--- a/mm/memfd.c ++++ b/mm/memfd.c +@@ -286,7 +286,7 @@ static int memfd_add_seals(struct file * + } + + /* +- * SEAL_EXEC implys SEAL_WRITE, making W^X from the start. ++ * SEAL_EXEC implies SEAL_WRITE, making W^X from the start. + */ + if (seals & F_SEAL_EXEC && inode->i_mode & 0111) + seals |= F_SEAL_SHRINK|F_SEAL_GROW|F_SEAL_WRITE|F_SEAL_FUTURE_WRITE; +@@ -364,7 +364,7 @@ static int check_write_seal(unsigned lon + unsigned long vm_flags = *vm_flags_ptr; + unsigned long mask = vm_flags & (VM_SHARED | VM_WRITE); + +- /* If a private matting then writability is irrelevant. */ ++ /* If a private mapping then writability is irrelevant. */ + if (!(mask & VM_SHARED)) + return 0; + diff --git a/queue-6.12/mm-perform-all-memfd-seal-checks-in-a-single-place.patch b/queue-6.12/mm-perform-all-memfd-seal-checks-in-a-single-place.patch new file mode 100644 index 0000000000..4a8c151266 --- /dev/null +++ b/queue-6.12/mm-perform-all-memfd-seal-checks-in-a-single-place.patch @@ -0,0 +1,299 @@ +From stable+bounces-260501-greg=kroah.com@vger.kernel.org Thu Jun 4 16:16:27 2026 +From: Sasha Levin +Date: Thu, 4 Jun 2026 09:54:19 -0400 +Subject: mm: perform all memfd seal checks in a single place +To: stable@vger.kernel.org +Cc: Lorenzo Stoakes , "Isaac J. Manjarres" , Hugh Dickins , Jann Horn , Kalesh Singh , "Liam R. Howlett" , Muchun Song , Vlastimil Babka , Jeff Xu , Andrew Morton , Sasha Levin +Message-ID: <20260604135421.3490773-1-sashal@kernel.org> + +From: Lorenzo Stoakes + +[ Upstream commit fa00b8ef1803fe133b4897c25227aa0d298dd093 ] + +We no longer actually need to perform these checks in the f_op->mmap() +hook any longer. + +We already moved the operation which clears VM_MAYWRITE on a read-only +mapping of a write-sealed memfd in order to work around the restrictions +imposed by commit 5de195060b2e ("mm: resolve faulty mmap_region() error +path behaviour"). + +There is no reason for us not to simply go ahead and additionally check to +see if any pre-existing seals are in place here rather than defer this to +the f_op->mmap() hook. + +By doing this we remove more logic from shmem_mmap() which doesn't belong +there, as well as doing the same for hugetlbfs_file_mmap(). We also +remove dubious shared logic in mm.h which simply does not belong there +either. + +It makes sense to do these checks at the earliest opportunity, we know +these are shmem (or hugetlbfs) mappings whose relevant VMA flags will not +change from the invoking do_mmap() so there is simply no need to wait. + +This also means the implementation of further memfd seal flags can be done +within mm/memfd.c and also have the opportunity to modify VMA flags as +necessary early in the mapping logic. + +[lorenzo.stoakes@oracle.com: fix typos in !memfd inline stub] + Link: https://lkml.kernel.org/r/7dee6c5d-480b-4c24-b98e-6fa47dbd8a23@lucifer.local +Link: https://lkml.kernel.org/r/20241206212846.210835-1-lorenzo.stoakes@oracle.com +Signed-off-by: Lorenzo Stoakes +Tested-by: Isaac J. Manjarres +Cc: Hugh Dickins +Cc: Jann Horn +Cc: Kalesh Singh +Cc: Liam R. Howlett +Cc: Muchun Song +Cc: Vlastimil Babka +Cc: Jeff Xu +Signed-off-by: Andrew Morton +Stable-dep-of: 3b041514cb6e ("memfd: deny writeable mappings when implying SEAL_WRITE") +Signed-off-by: Sasha Levin +Signed-off-by: Greg Kroah-Hartman +--- + fs/hugetlbfs/inode.c | 5 ---- + include/linux/memfd.h | 23 ++++++++++---------- + include/linux/mm.h | 55 -------------------------------------------------- + mm/memfd.c | 44 +++++++++++++++++++++++++++++++++++++++- + mm/mmap.c | 12 ++++++++-- + mm/shmem.c | 6 ----- + 6 files changed, 63 insertions(+), 82 deletions(-) + +--- a/fs/hugetlbfs/inode.c ++++ b/fs/hugetlbfs/inode.c +@@ -96,7 +96,6 @@ static const struct fs_parameter_spec hu + static int hugetlbfs_file_mmap(struct file *file, struct vm_area_struct *vma) + { + struct inode *inode = file_inode(file); +- struct hugetlbfs_inode_info *info = HUGETLBFS_I(inode); + loff_t len, vma_len; + int ret; + struct hstate *h = hstate_file(file); +@@ -113,10 +112,6 @@ static int hugetlbfs_file_mmap(struct fi + vm_flags_set(vma, VM_HUGETLB | VM_DONTEXPAND); + vma->vm_ops = &hugetlb_vm_ops; + +- ret = seal_check_write(info->seals, vma); +- if (ret) +- return ret; +- + /* + * page based offset in vm_pgoff could be sufficiently large to + * overflow a loff_t when converted to byte offset. This can +--- a/include/linux/memfd.h ++++ b/include/linux/memfd.h +@@ -7,7 +7,14 @@ + #ifdef CONFIG_MEMFD_CREATE + extern long memfd_fcntl(struct file *file, unsigned int cmd, unsigned int arg); + struct folio *memfd_alloc_folio(struct file *memfd, pgoff_t idx); +-unsigned int *memfd_file_seals_ptr(struct file *file); ++/* ++ * Check for any existing seals on mmap, return an error if access is denied due ++ * to sealing, or 0 otherwise. ++ * ++ * We also update VMA flags if appropriate by manipulating the VMA flags pointed ++ * to by vm_flags_ptr. ++ */ ++int memfd_check_seals_mmap(struct file *file, unsigned long *vm_flags_ptr); + #else + static inline long memfd_fcntl(struct file *f, unsigned int c, unsigned int a) + { +@@ -17,19 +24,11 @@ static inline struct folio *memfd_alloc_ + { + return ERR_PTR(-EINVAL); + } +- +-static inline unsigned int *memfd_file_seals_ptr(struct file *file) ++static inline int memfd_check_seals_mmap(struct file *file, ++ unsigned long *vm_flags_ptr) + { +- return NULL; ++ return 0; + } + #endif + +-/* Retrieve memfd seals associated with the file, if any. */ +-static inline unsigned int memfd_file_seals(struct file *file) +-{ +- unsigned int *sealsp = memfd_file_seals_ptr(file); +- +- return sealsp ? *sealsp : 0; +-} +- + #endif /* __LINUX_MEMFD_H */ +--- a/include/linux/mm.h ++++ b/include/linux/mm.h +@@ -4140,61 +4140,6 @@ void mem_dump_obj(void *object); + static inline void mem_dump_obj(void *object) {} + #endif + +-static inline bool is_write_sealed(int seals) +-{ +- return seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE); +-} +- +-/** +- * is_readonly_sealed - Checks whether write-sealed but mapped read-only, +- * in which case writes should be disallowing moving +- * forwards. +- * @seals: the seals to check +- * @vm_flags: the VMA flags to check +- * +- * Returns whether readonly sealed, in which case writess should be disallowed +- * going forward. +- */ +-static inline bool is_readonly_sealed(int seals, vm_flags_t vm_flags) +-{ +- /* +- * Since an F_SEAL_[FUTURE_]WRITE sealed memfd can be mapped as +- * MAP_SHARED and read-only, take care to not allow mprotect to +- * revert protections on such mappings. Do this only for shared +- * mappings. For private mappings, don't need to mask +- * VM_MAYWRITE as we still want them to be COW-writable. +- */ +- if (is_write_sealed(seals) && +- ((vm_flags & (VM_SHARED | VM_WRITE)) == VM_SHARED)) +- return true; +- +- return false; +-} +- +-/** +- * seal_check_write - Check for F_SEAL_WRITE or F_SEAL_FUTURE_WRITE flags and +- * handle them. +- * @seals: the seals to check +- * @vma: the vma to operate on +- * +- * Check whether F_SEAL_WRITE or F_SEAL_FUTURE_WRITE are set; if so, do proper +- * check/handling on the vma flags. Return 0 if check pass, or <0 for errors. +- */ +-static inline int seal_check_write(int seals, struct vm_area_struct *vma) +-{ +- if (!is_write_sealed(seals)) +- return 0; +- +- /* +- * New PROT_WRITE and MAP_SHARED mmaps are not allowed when +- * write seals are active. +- */ +- if ((vma->vm_flags & VM_SHARED) && (vma->vm_flags & VM_WRITE)) +- return -EPERM; +- +- return 0; +-} +- + #ifdef CONFIG_ANON_VMA_NAME + int madvise_set_anon_name(struct mm_struct *mm, unsigned long start, + unsigned long len_in, +--- a/mm/memfd.c ++++ b/mm/memfd.c +@@ -197,7 +197,7 @@ static int memfd_wait_for_pins(struct ad + return error; + } + +-unsigned int *memfd_file_seals_ptr(struct file *file) ++static unsigned int *memfd_file_seals_ptr(struct file *file) + { + if (shmem_file(file)) + return &SHMEM_I(file_inode(file))->seals; +@@ -354,6 +354,48 @@ static int check_sysctl_memfd_noexec(uns + return 0; + } + ++static inline bool is_write_sealed(unsigned int seals) ++{ ++ return seals & (F_SEAL_WRITE | F_SEAL_FUTURE_WRITE); ++} ++ ++static int check_write_seal(unsigned long *vm_flags_ptr) ++{ ++ unsigned long vm_flags = *vm_flags_ptr; ++ unsigned long mask = vm_flags & (VM_SHARED | VM_WRITE); ++ ++ /* If a private matting then writability is irrelevant. */ ++ if (!(mask & VM_SHARED)) ++ return 0; ++ ++ /* ++ * New PROT_WRITE and MAP_SHARED mmaps are not allowed when ++ * write seals are active. ++ */ ++ if (mask & VM_WRITE) ++ return -EPERM; ++ ++ /* ++ * This is a read-only mapping, disallow mprotect() from making a ++ * write-sealed mapping writable in future. ++ */ ++ *vm_flags_ptr &= ~VM_MAYWRITE; ++ ++ return 0; ++} ++ ++int memfd_check_seals_mmap(struct file *file, unsigned long *vm_flags_ptr) ++{ ++ int err = 0; ++ unsigned int *seals_ptr = memfd_file_seals_ptr(file); ++ unsigned int seals = seals_ptr ? *seals_ptr : 0; ++ ++ if (is_write_sealed(seals)) ++ err = check_write_seal(vm_flags_ptr); ++ ++ return err; ++} ++ + SYSCALL_DEFINE2(memfd_create, + const char __user *, uname, + unsigned int, flags) +--- a/mm/mmap.c ++++ b/mm/mmap.c +@@ -369,8 +369,8 @@ unsigned long do_mmap(struct file *file, + + if (file) { + struct inode *inode = file_inode(file); +- unsigned int seals = memfd_file_seals(file); + unsigned long flags_mask; ++ int err; + + if (!file_mmap_ok(file, inode, pgoff, len)) + return -EOVERFLOW; +@@ -410,8 +410,6 @@ unsigned long do_mmap(struct file *file, + vm_flags |= VM_SHARED | VM_MAYSHARE; + if (!(file->f_mode & FMODE_WRITE)) + vm_flags &= ~(VM_MAYWRITE | VM_SHARED); +- else if (is_readonly_sealed(seals, vm_flags)) +- vm_flags &= ~VM_MAYWRITE; + fallthrough; + case MAP_PRIVATE: + if (!(file->f_mode & FMODE_READ)) +@@ -431,6 +429,14 @@ unsigned long do_mmap(struct file *file, + default: + return -EINVAL; + } ++ ++ /* ++ * Check to see if we are violating any seals and update VMA ++ * flags if necessary to avoid future seal violations. ++ */ ++ err = memfd_check_seals_mmap(file, &vm_flags); ++ if (err) ++ return (unsigned long)err; + } else { + switch (flags & MAP_TYPE) { + case MAP_SHARED: +--- a/mm/shmem.c ++++ b/mm/shmem.c +@@ -2820,12 +2820,6 @@ out_nomem: + static int shmem_mmap(struct file *file, struct vm_area_struct *vma) + { + struct inode *inode = file_inode(file); +- struct shmem_inode_info *info = SHMEM_I(inode); +- int ret; +- +- ret = seal_check_write(info->seals, vma); +- if (ret) +- return ret; + + file_accessed(file); + /* This is anonymous shared memory if it is unlinked at the time of mmap */ diff --git a/queue-6.12/series b/queue-6.12/series index 332f4ae5cf..cbc0088a5d 100644 --- a/queue-6.12/series +++ b/queue-6.12/series @@ -299,3 +299,9 @@ scsi-target-iscsi-fix-crc-overread-and-double-free-in-iscsit_handle_text_cmd.pat usb-typec-ucsi-don-t-update-power_supply-on-power-role-change-if-not-connected.patch x86-alternatives-rename-apply_relocation-to-text_poke_apply_relocation.patch x86-ftrace-relocate-rip-relative-percpu-refs-in-dynamic-trampolines.patch +hwmon-pmbus-adm1266-serialize-sequencer_state-debugfs-read-with-pmbus_lock.patch +hwmon-pmbus-adm1266-serialize-nvmem-blackbox-read-with-pmbus_lock.patch +hwmon-pmbus-adm1266-serialize-gpio-pmbus-accesses-with-pmbus_lock.patch +mm-perform-all-memfd-seal-checks-in-a-single-place.patch +mm-memfd-fix-spelling-and-grammatical-issues.patch +memfd-deny-writeable-mappings-when-implying-seal_write.patch