* [PATCH v4 0/3] liveupdate: prevent double preservation
@ 2026-03-26 16:39 Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 1/3] liveupdate: prevent double management of files Pasha Tatashin
` (2 more replies)
0 siblings, 3 replies; 5+ messages in thread
From: Pasha Tatashin @ 2026-03-26 16:39 UTC (permalink / raw)
To: linux-kselftest, rppt, shuah, akpm, linux-mm, linux-kernel,
pasha.tatashin, dmatlack, pratyush, skhawaja
Currently, LUO does not prevent the same file from being managed twice
across different active sessions.
Because LUO preserves files of absolutely different types: memfd, and
upcoming vfiofd [1], iommufd [2], guestmefd (and possible kvmfd/cpufd).
There is no common private data or guarantee on how to prevent that the
same file is not preserved twice beside using inode or some slower and
expensive method like hashtables.
[1] https://lore.kernel.org/all/20260129212510.967611-1-dmatlack@google.com
[2] https://lore.kernel.org/all/20260203220948.2176157-1-skhawaja@google.com
Changelog:
v4:
- Added get_id() callback to struct liveupdate_file_ops to allow handlers
to define unique identification for files (e.g. via inode).
- Implemented get_id() for memfd_luo to use the inode pointer.
Pasha Tatashin (3):
liveupdate: prevent double management of files
memfd: implement get_id for memfd_luo
selftests: liveupdate: add test for double preservation
include/linux/liveupdate.h | 2 ++
kernel/liveupdate/luo_file.c | 32 ++++++++++++++++++++++++++++++--
mm/memfd_luo.c | 6 ++++++
tools/testing/selftests/liveupdate/liveupdate.c | 41 +++++++++++++++++++++++++++++++++++++++++
4 files changed, 79 insertions(+), 2 deletions(-)
Pasha Tatashin (3):
liveupdate: prevent double management of files
memfd: implement get_id for memfd_luo
selftests: liveupdate: add test for double preservation
include/linux/liveupdate.h | 2 +
kernel/liveupdate/luo_file.c | 32 ++++++++++++++-
mm/memfd_luo.c | 6 +++
.../testing/selftests/liveupdate/liveupdate.c | 41 +++++++++++++++++++
4 files changed, 79 insertions(+), 2 deletions(-)
base-commit: 0138af2472dfdef0d56fc4697416eaa0ff2589bd
--
2.43.0
^ permalink raw reply [flat|nested] 5+ messages in thread
* [PATCH v4 1/3] liveupdate: prevent double management of files
2026-03-26 16:39 [PATCH v4 0/3] liveupdate: prevent double preservation Pasha Tatashin
@ 2026-03-26 16:39 ` Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 2/3] memfd: implement get_id for memfd_luo Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 3/3] selftests: liveupdate: add test for double preservation Pasha Tatashin
2 siblings, 0 replies; 5+ messages in thread
From: Pasha Tatashin @ 2026-03-26 16:39 UTC (permalink / raw)
To: linux-kselftest, rppt, shuah, akpm, linux-mm, linux-kernel,
pasha.tatashin, dmatlack, pratyush, skhawaja
Currently, LUO does not prevent the same file from being managed twice
across different active sessions.
Use a global xarray luo_preserved_files to keep track of file
identifiers being preserved by LUO. Update luo_preserve_file() to
check and insert the file identifier into this xarray when it is
preserved, and erase it in luo_file_unpreserve_files() when it is
released.
To allow handlers to define what constitutes a "unique" file (e.g.,
different struct file objects pointing to the same hardware resource),
add a get_id() callback to struct liveupdate_file_ops. If not
provided, the default identifier is the struct file pointer itself.
This ensures that the same file (or resource) cannot be managed by
multiple sessions. If another session attempts to preserve an already
managed file, it will now fail with -EBUSY.
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
include/linux/liveupdate.h | 2 ++
kernel/liveupdate/luo_file.c | 32 ++++++++++++++++++++++++++++++--
2 files changed, 32 insertions(+), 2 deletions(-)
diff --git a/include/linux/liveupdate.h b/include/linux/liveupdate.h
index dd11fdc76a5f..61325ad26526 100644
--- a/include/linux/liveupdate.h
+++ b/include/linux/liveupdate.h
@@ -63,6 +63,7 @@ struct liveupdate_file_op_args {
* finish, in order to do successful finish calls for all
* resources in the session.
* @finish: Required. Final cleanup in the new kernel.
+ * @get_id: Optional. Returns a unique identifier for the file.
* @owner: Module reference
*
* All operations (except can_preserve) receive a pointer to a
@@ -78,6 +79,7 @@ struct liveupdate_file_ops {
int (*retrieve)(struct liveupdate_file_op_args *args);
bool (*can_finish)(struct liveupdate_file_op_args *args);
void (*finish)(struct liveupdate_file_op_args *args);
+ unsigned long (*get_id)(struct file *file);
struct module *owner;
};
diff --git a/kernel/liveupdate/luo_file.c b/kernel/liveupdate/luo_file.c
index 5acee4174bf0..b02e2891cdb8 100644
--- a/kernel/liveupdate/luo_file.c
+++ b/kernel/liveupdate/luo_file.c
@@ -110,10 +110,14 @@
#include <linux/sizes.h>
#include <linux/slab.h>
#include <linux/string.h>
+#include <linux/xarray.h>
#include "luo_internal.h"
static LIST_HEAD(luo_file_handler_list);
+/* Keep track of files being preserved by LUO */
+static DEFINE_XARRAY(luo_preserved_files);
+
/* 2 4K pages, give space for 128 files per file_set */
#define LUO_FILE_PGCNT 2ul
#define LUO_FILE_MAX \
@@ -203,6 +207,12 @@ static void luo_free_files_mem(struct luo_file_set *file_set)
file_set->files = NULL;
}
+static unsigned long luo_get_id(struct liveupdate_file_handler *fh,
+ struct file *file)
+{
+ return fh->ops->get_id ? fh->ops->get_id(file) : (unsigned long)file;
+}
+
static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
{
struct luo_file *iter;
@@ -248,6 +258,7 @@ static bool luo_token_is_used(struct luo_file_set *file_set, u64 token)
* Context: Can be called from an ioctl handler during normal system operation.
* Return: 0 on success. Returns a negative errno on failure:
* -EEXIST if the token is already used.
+ * -EBUSY if the file descriptor is already preserved by another session.
* -EBADF if the file descriptor is invalid.
* -ENOSPC if the file_set is full.
* -ENOENT if no compatible handler is found.
@@ -288,10 +299,15 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
if (err)
goto err_free_files_mem;
- err = luo_flb_file_preserve(fh);
+ err = xa_insert(&luo_preserved_files, luo_get_id(fh, file),
+ file, GFP_KERNEL);
if (err)
goto err_free_files_mem;
+ err = luo_flb_file_preserve(fh);
+ if (err)
+ goto err_erase_xa;
+
luo_file = kzalloc_obj(*luo_file);
if (!luo_file) {
err = -ENOMEM;
@@ -320,6 +336,8 @@ int luo_preserve_file(struct luo_file_set *file_set, u64 token, int fd)
kfree(luo_file);
err_flb_unpreserve:
luo_flb_file_unpreserve(fh);
+err_erase_xa:
+ xa_erase(&luo_preserved_files, luo_get_id(fh, file));
err_free_files_mem:
luo_free_files_mem(file_set);
err_fput:
@@ -363,6 +381,8 @@ void luo_file_unpreserve_files(struct luo_file_set *file_set)
luo_file->fh->ops->unpreserve(&args);
luo_flb_file_unpreserve(luo_file->fh);
+ xa_erase(&luo_preserved_files,
+ luo_get_id(luo_file->fh, luo_file->file));
list_del(&luo_file->list);
file_set->count--;
@@ -606,6 +626,11 @@ int luo_retrieve_file(struct luo_file_set *file_set, u64 token,
luo_file->file = args.file;
/* Get reference so we can keep this file in LUO until finish */
get_file(luo_file->file);
+
+ WARN_ON(xa_insert(&luo_preserved_files,
+ luo_get_id(luo_file->fh, luo_file->file),
+ luo_file->file, GFP_KERNEL));
+
*filep = luo_file->file;
luo_file->retrieve_status = 1;
@@ -701,8 +726,11 @@ int luo_file_finish(struct luo_file_set *file_set)
luo_file_finish_one(file_set, luo_file);
- if (luo_file->file)
+ if (luo_file->file) {
+ xa_erase(&luo_preserved_files,
+ luo_get_id(luo_file->fh, luo_file->file));
fput(luo_file->file);
+ }
list_del(&luo_file->list);
file_set->count--;
mutex_destroy(&luo_file->mutex);
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 2/3] memfd: implement get_id for memfd_luo
2026-03-26 16:39 [PATCH v4 0/3] liveupdate: prevent double preservation Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 1/3] liveupdate: prevent double management of files Pasha Tatashin
@ 2026-03-26 16:39 ` Pasha Tatashin
2026-04-03 18:32 ` Pratyush Yadav
2026-03-26 16:39 ` [PATCH v4 3/3] selftests: liveupdate: add test for double preservation Pasha Tatashin
2 siblings, 1 reply; 5+ messages in thread
From: Pasha Tatashin @ 2026-03-26 16:39 UTC (permalink / raw)
To: linux-kselftest, rppt, shuah, akpm, linux-mm, linux-kernel,
pasha.tatashin, dmatlack, pratyush, skhawaja
Memfds are identified by their underlying inode. Implement get_id
for memfd_luo to return the inode pointer. This prevents the same
memfd from being managed twice by LUO if the same inode is pointed
by multiple file objects.
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
mm/memfd_luo.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/mm/memfd_luo.c b/mm/memfd_luo.c
index b8edb9f981d7..6629ab4d8e30 100644
--- a/mm/memfd_luo.c
+++ b/mm/memfd_luo.c
@@ -529,6 +529,11 @@ static bool memfd_luo_can_preserve(struct liveupdate_file_handler *handler,
return shmem_file(file) && !inode->i_nlink;
}
+static unsigned long memfd_luo_get_id(struct file *file)
+{
+ return (unsigned long)file_inode(file);
+}
+
static const struct liveupdate_file_ops memfd_luo_file_ops = {
.freeze = memfd_luo_freeze,
.finish = memfd_luo_finish,
@@ -536,6 +541,7 @@ static const struct liveupdate_file_ops memfd_luo_file_ops = {
.preserve = memfd_luo_preserve,
.unpreserve = memfd_luo_unpreserve,
.can_preserve = memfd_luo_can_preserve,
+ .get_id = memfd_luo_get_id,
.owner = THIS_MODULE,
};
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* [PATCH v4 3/3] selftests: liveupdate: add test for double preservation
2026-03-26 16:39 [PATCH v4 0/3] liveupdate: prevent double preservation Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 1/3] liveupdate: prevent double management of files Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 2/3] memfd: implement get_id for memfd_luo Pasha Tatashin
@ 2026-03-26 16:39 ` Pasha Tatashin
2 siblings, 0 replies; 5+ messages in thread
From: Pasha Tatashin @ 2026-03-26 16:39 UTC (permalink / raw)
To: linux-kselftest, rppt, shuah, akpm, linux-mm, linux-kernel,
pasha.tatashin, dmatlack, pratyush, skhawaja
Verify that a file can only be preserved once across all active
sessions. Attempting to preserve it a second time, whether in the same
or a different session, should fail with EBUSY.
Reviewed-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Samiullah Khawaja <skhawaja@google.com>
Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
---
.../testing/selftests/liveupdate/liveupdate.c | 41 +++++++++++++++++++
1 file changed, 41 insertions(+)
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
index c2878e3d5ef9..37c808fbe1e9 100644
--- a/tools/testing/selftests/liveupdate/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/liveupdate.c
@@ -345,4 +345,45 @@ TEST_F(liveupdate_device, preserve_unsupported_fd)
ASSERT_EQ(close(session_fd), 0);
}
+/*
+ * Test Case: Prevent Double Preservation
+ *
+ * Verifies that a file (memfd) can only be preserved once across all active
+ * sessions. Attempting to preserve it a second time, whether in the same or
+ * a different session, should fail with EBUSY.
+ */
+TEST_F(liveupdate_device, prevent_double_preservation)
+{
+ int session_fd1, session_fd2, mem_fd;
+ int ret;
+
+ self->fd1 = open(LIVEUPDATE_DEV, O_RDWR);
+ if (self->fd1 < 0 && errno == ENOENT)
+ SKIP(return, "%s does not exist", LIVEUPDATE_DEV);
+ ASSERT_GE(self->fd1, 0);
+
+ session_fd1 = create_session(self->fd1, "double-preserve-session-1");
+ ASSERT_GE(session_fd1, 0);
+ session_fd2 = create_session(self->fd1, "double-preserve-session-2");
+ ASSERT_GE(session_fd2, 0);
+
+ mem_fd = memfd_create("test-memfd", 0);
+ ASSERT_GE(mem_fd, 0);
+
+ /* First preservation should succeed */
+ ASSERT_EQ(preserve_fd(session_fd1, mem_fd, 0x1111), 0);
+
+ /* Second preservation in a different session should fail with EBUSY */
+ ret = preserve_fd(session_fd2, mem_fd, 0x2222);
+ EXPECT_EQ(ret, -EBUSY);
+
+ /* Second preservation in the same session (different token) should fail with EBUSY */
+ ret = preserve_fd(session_fd1, mem_fd, 0x3333);
+ EXPECT_EQ(ret, -EBUSY);
+
+ ASSERT_EQ(close(mem_fd), 0);
+ ASSERT_EQ(close(session_fd1), 0);
+ ASSERT_EQ(close(session_fd2), 0);
+}
+
TEST_HARNESS_MAIN
--
2.43.0
^ permalink raw reply related [flat|nested] 5+ messages in thread
* Re: [PATCH v4 2/3] memfd: implement get_id for memfd_luo
2026-03-26 16:39 ` [PATCH v4 2/3] memfd: implement get_id for memfd_luo Pasha Tatashin
@ 2026-04-03 18:32 ` Pratyush Yadav
0 siblings, 0 replies; 5+ messages in thread
From: Pratyush Yadav @ 2026-04-03 18:32 UTC (permalink / raw)
To: Pasha Tatashin
Cc: linux-kselftest, rppt, shuah, akpm, linux-mm, linux-kernel,
dmatlack, pratyush, skhawaja
On Thu, Mar 26 2026, Pasha Tatashin wrote:
> Memfds are identified by their underlying inode. Implement get_id
> for memfd_luo to return the inode pointer. This prevents the same
> memfd from being managed twice by LUO if the same inode is pointed
> by multiple file objects.
>
> Signed-off-by: Pasha Tatashin <pasha.tatashin@soleen.com>
Reviewed-by: Pratyush Yadav (Google) <pratyush@kernel.org>
[...]
--
Regards,
Pratyush Yadav
^ permalink raw reply [flat|nested] 5+ messages in thread
end of thread, other threads:[~2026-04-03 18:32 UTC | newest]
Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-26 16:39 [PATCH v4 0/3] liveupdate: prevent double preservation Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 1/3] liveupdate: prevent double management of files Pasha Tatashin
2026-03-26 16:39 ` [PATCH v4 2/3] memfd: implement get_id for memfd_luo Pasha Tatashin
2026-04-03 18:32 ` Pratyush Yadav
2026-03-26 16:39 ` [PATCH v4 3/3] selftests: liveupdate: add test for double preservation Pasha Tatashin
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox