[PATCH] mm/memfd_luo: carry the exec-bit state in the preserved record
sashiko-bot at kernel.org
sashiko-bot at kernel.org
Tue Oct 13 17:49:17 PDT 2026
Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [High] mm: TOCTOU race in memfd_luo_preserve loses fchmod and seals updates
- [Medium] mm/memfd_luo: leak of preserved folios in memfd_luo_retrieve() error paths
--
commit b09cba94dd95aadc45f383b05eb9e6f205bf88e7
Author: Haolong Wang <18766350203 at 163.com>
Subject: mm/memfd_luo: carry the exec-bit state in the preserved record
This commit preserves the execution bits of a memfd during a KHO live
update. It records the exec-bit state in the memfd_luo_ser structure and
applies it to the fresh inode during restore before re-applying seals,
ensuring the W^X policy behaves correctly.
> diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
> --- a/mm/memfd_luo.c
> +++ b/mm/memfd_luo.c
> @@ -299,6 +299,17 @@ static int memfd_luo_preserve(struct liveupdate_file_op_args *args)
> ser->size = inode_size;
> ser->seals = seals;
>
> + /*
> + * F_SEAL_EXEC freezes the exec bits as they are at sealing time, so
> + * the restore has to reproduce them. Record whether the inode had
> + * exec bits here; the restore sets the mode of the fresh inode
> + * accordingly before re-applying the seals. ser is zero-initialized,
> + * so a clear bit means the bits were clear (or the record predates
> + * this flag -- the safe reading for those is also "no exec bits").
> + */
> + if (inode->i_mode & 0111)
> + ser->flags |= MEMFD_LUO_FL_EXEC_BIT;
> +
[Severity: High]
Can a concurrent userspace modification race with this early caching?
The i_mode is read and cached here, before dropping the inode_lock. Shortly
after, shmem_freeze() is called. However, SHMEM_F_MAPPING_FROZEN ignores
ATTR_MODE in shmem_setattr() and is not checked in memfd_add_seals().
Because memfd_luo_freeze() blindly updates only f_pos without re-evaluating
the mode or seals:
mm/memfd_luo.c:memfd_luo_freeze() {
...
ser->pos = args->file->f_pos;
...
}
Could userspace modify the mode via fchmod or add seals between the preserve
and freeze phases, causing the restore process to lose those updates and
break security policies like the W^X rule?
[ ... ]
> @@ -542,6 +556,19 @@ static int memfd_luo_retrieve(struct liveupdate_file_op_args *args)
> goto free_ser;
> }
>
> + /*
> + * Reproduce the exec bits before the seals are re-applied: F_SEAL_EXEC
> + * freezes the bits as they were at sealing time, and the W^X rule in
> + * memfd_add_seals() looks at the mode when it decides whether to imply
> + * the write seals. Setting the mode here, directly on the fresh
> + * anonymous inode, is safe -- the file has not been published and no
> + * other thread can reach it yet.
> + */
> + if (ser->flags & MEMFD_LUO_FL_EXEC_BIT)
> + file->f_inode->i_mode |= 0111;
> + else
> + file->f_inode->i_mode &= ~0111;
> +
> err = memfd_add_seals(file, ser->seals);
> if (err) {
> pr_err("failed to add seals: %pe\n", ERR_PTR(err));
> goto put_file;
> }
[Severity: Medium]
Do these error paths leak the physical folios tracked by ser->folios?
When jumping to free_ser or put_file on failure, kho_restore_free(ser) is
called, but there is no call to restore the vmalloc metadata via
kho_restore_vmalloc() and free the physical folios.
Looking at memfd_luo_finish(), the driver explicitly expects retrieve() to
clean up its own folios on failure:
mm/memfd_luo.c:memfd_luo_finish() {
/*
* If retrieve was successful, nothing to do. If it failed, retrieve()
* already cleaned up everything it could. So nothing to do there
* either. Only need to clean up when retrieve was not called.
*/
if (args->retrieve_status)
return;
...
}
Will failing at memfd_alloc_file() or memfd_add_seals() leave these
KHO-preserved folios permanently reserved in memory?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261014003558.357783-1-18766350203@163.com?part=1
More information about the kexec
mailing list