Verify the user argument support in LIVEUPDATE_SESSION_PRESERVE_FD and
LIVEUPDATE_SESSION_RETRIEVE_FD. Add luo_session_preserve_fd_arg() and
luo_session_retrieve_fd_arg() helpers to libliveupdate so tests can pass
a handler-specific argument.

Add a preserve_memfd_with_arg test case to verify that memfd
preservation rejects a non-zero argument with -EOPNOTSUPP, accepts an
explicit zero argument, and remains compatible with callers passing the
legacy struct size up to the token field.

Signed-off-by: Pasha Tatashin <[email protected]>
---
 .../liveupdate/lib/include/libliveupdate.h    |  3 ++
 .../selftests/liveupdate/lib/lu_utils.c       | 17 ++++++-
 .../testing/selftests/liveupdate/liveupdate.c | 44 +++++++++++++++++++
 3 files changed, 62 insertions(+), 2 deletions(-)

diff --git a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h 
b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
index 15a7db3a6b3e8..8a38268e89dee 100644
--- a/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
+++ b/tools/testing/selftests/liveupdate/lib/include/libliveupdate.h
@@ -30,7 +30,10 @@ int luo_session_freeze(int session_fd);
 
 int luo_ensure_nofile_limit(long min_limit);
 int luo_session_preserve_fd(int session_fd, int fd, __u64 token);
+int luo_session_preserve_fd_arg(int session_fd, int fd, __u64 token,
+                               __u64 user_arg);
 int luo_session_retrieve_fd(int session_fd, __u64 token);
+int luo_session_retrieve_fd_arg(int session_fd, __u64 token, __u64 user_arg);
 
 int create_and_preserve_memfd(int session_fd, int token, const char *data);
 int restore_and_verify_memfd(int session_fd, int token, const char 
*expected_data);
diff --git a/tools/testing/selftests/liveupdate/lib/lu_utils.c 
b/tools/testing/selftests/liveupdate/lib/lu_utils.c
index 6315746ff08f8..5c6f8bf80b297 100644
--- a/tools/testing/selftests/liveupdate/lib/lu_utils.c
+++ b/tools/testing/selftests/liveupdate/lib/lu_utils.c
@@ -79,12 +79,14 @@ int luo_retrieve_session(int luo_fd, const char *name)
        return arg.fd;
 }
 
-int luo_session_preserve_fd(int session_fd, int fd, __u64 token)
+int luo_session_preserve_fd_arg(int session_fd, int fd, __u64 token,
+                               __u64 user_arg)
 {
        struct liveupdate_session_preserve_fd arg = {
                .size = sizeof(arg),
                .fd = fd,
                .token = token,
+               .arg = user_arg,
        };
 
        if (ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &arg))
@@ -93,11 +95,17 @@ int luo_session_preserve_fd(int session_fd, int fd, __u64 
token)
        return 0;
 }
 
-int luo_session_retrieve_fd(int session_fd, __u64 token)
+int luo_session_preserve_fd(int session_fd, int fd, __u64 token)
+{
+       return luo_session_preserve_fd_arg(session_fd, fd, token, 0);
+}
+
+int luo_session_retrieve_fd_arg(int session_fd, __u64 token, __u64 user_arg)
 {
        struct liveupdate_session_retrieve_fd arg = {
                .size = sizeof(arg),
                .token = token,
+               .arg = user_arg,
        };
 
        if (ioctl(session_fd, LIVEUPDATE_SESSION_RETRIEVE_FD, &arg))
@@ -106,6 +114,11 @@ int luo_session_retrieve_fd(int session_fd, __u64 token)
        return arg.fd;
 }
 
+int luo_session_retrieve_fd(int session_fd, __u64 token)
+{
+       return luo_session_retrieve_fd_arg(session_fd, token, 0);
+}
+
 /* Helper function to get a session name via ioctl. */
 int luo_get_session_name(int session_fd, char *name, size_t name_len)
 {
diff --git a/tools/testing/selftests/liveupdate/liveupdate.c 
b/tools/testing/selftests/liveupdate/liveupdate.c
index 9de068f31c3ec..83e0978f3818d 100644
--- a/tools/testing/selftests/liveupdate/liveupdate.c
+++ b/tools/testing/selftests/liveupdate/liveupdate.c
@@ -20,6 +20,7 @@
 
 #include <errno.h>
 #include <fcntl.h>
+#include <stddef.h>
 #include <string.h>
 #include <sys/ioctl.h>
 #include <unistd.h>
@@ -570,4 +571,47 @@ TEST_F(liveupdate_device, session_freeze)
        ASSERT_EQ(close(mem_fd2), 0);
 }
 
+/*
+ * Test Case: Preserve MemFD with User Argument
+ *
+ * Verifies that passing a non-zero user argument to memfd preservation fails
+ * with -EOPNOTSUPP, while passing a zero argument or using the minimum struct
+ * size without the arg field succeeds.
+ */
+TEST_F(liveupdate_device, preserve_memfd_with_arg)
+{
+       struct liveupdate_session_preserve_fd min_arg = {};
+       int session_fd, mem_fd1, mem_fd2;
+
+       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_fd = luo_create_session(self->fd1, "preserve-arg-test");
+       ASSERT_GE(session_fd, 0);
+
+       mem_fd1 = memfd_create("arg-memfd-1", 0);
+       ASSERT_GE(mem_fd1, 0);
+
+       /* Non-zero arg is not supported by memfd handler */
+       EXPECT_EQ(luo_session_preserve_fd_arg(session_fd, mem_fd1, 0x1111, 1),
+                 -EOPNOTSUPP);
+
+       /* Legacy struct size (up to token) should zero-fill arg and succeed */
+       min_arg.size = offsetof(struct liveupdate_session_preserve_fd, arg);
+       min_arg.fd = mem_fd1;
+       min_arg.token = 0x1111;
+       ASSERT_EQ(ioctl(session_fd, LIVEUPDATE_SESSION_PRESERVE_FD, &min_arg), 
0);
+
+       /* Explicit zero arg with full struct size should also succeed */
+       mem_fd2 = memfd_create("arg-memfd-2", 0);
+       ASSERT_GE(mem_fd2, 0);
+       ASSERT_EQ(luo_session_preserve_fd_arg(session_fd, mem_fd2, 0x2222, 0), 
0);
+
+       ASSERT_EQ(close(session_fd), 0);
+       ASSERT_EQ(close(mem_fd1), 0);
+       ASSERT_EQ(close(mem_fd2), 0);
+}
+
 TEST_HARNESS_MAIN
-- 
2.56.0.385.gd3acb90ef8-goog


Reply via email to