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

