[PATCH v7 4/4] selftests/liveupdate: add test cases for LIVEUPDATE_SESSION_GET_NAME
Pasha Tatashin
pasha.tatashin at soleen.com
Sat Apr 18 08:50:22 PDT 2026
On 04-18 15:09, luca.boccassi at gmail.com wrote:
> From: Luca Boccassi <luca.boccassi at gmail.com>
>
> Verify that the new LIVEUPDATE_SESSION_GET_NAME ioctl works
> as expected via new test cases in the existing liveupdate selftest.
>
> Signed-off-by: Luca Boccassi <luca.boccassi at gmail.com>
> ---
> v5: merge with LUO_SESSION_MAGIC series as they both change the same
> unit test file, to avoid merge conflicts
> split into separate patch
> v6: add more test cases as suggested
> more verbose commit message
>
> .../testing/selftests/liveupdate/liveupdate.c | 138 ++++++++++++++++++
> 1 file changed, 138 insertions(+)
>
> diff --git a/tools/testing/selftests/liveupdate/liveupdate.c b/tools/testing/selftests/liveupdate/liveupdate.c
> index d132b4685f76..ffbcbd465c9b 100644
> --- a/tools/testing/selftests/liveupdate/liveupdate.c
> +++ b/tools/testing/selftests/liveupdate/liveupdate.c
> @@ -105,6 +105,22 @@ static int create_session(int lu_fd, const char *name)
> return args.fd;
> }
>
> +/* Helper function to get a session name via ioctl. */
> +static int get_session_name(int session_fd, char *name, size_t name_len)
> +{
> + struct liveupdate_session_get_name args = {};
> +
> + args.size = sizeof(args);
> +
> + if (ioctl(session_fd, LIVEUPDATE_SESSION_GET_NAME, &args))
> + return -errno;
> +
> + strncpy(name, (char *)args.name, name_len - 1);
> + name[name_len - 1] = '\0';
> +
> + return 0;
> +}
> +
> /*
> * Test Case: Create Duplicate Session
> *
> @@ -385,4 +401,126 @@ TEST_F(liveupdate_device, session_fstat)
> ASSERT_EQ(close(session_fd2), 0);
> }
>
> +/*
> + * Test Case: Get Session Name
> + *
> + * Verifies that the full session name can be retrieved from a session file
> + * descriptor via ioctl.
> + */
> +TEST_F(liveupdate_device, get_session_name)
> +{
> + char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH] = {};
> + const char *session_name = "get-name-test-session";
> + int session_fd;
> +
> + 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 = create_session(self->fd1, session_name);
> + ASSERT_GE(session_fd, 0);
> +
> + ASSERT_EQ(get_session_name(session_fd, name_buf, sizeof(name_buf)), 0);
> + ASSERT_STREQ(name_buf, session_name);
> +
> + ASSERT_EQ(close(session_fd), 0);
> +}
> +
> +/*
> + * Test Case: Get Session Name at Maximum Length
> + *
> + * Verifies that a session name using the full LIVEUPDATE_SESSION_NAME_LENGTH
> + * (minus the null terminator) can be correctly retrieved.
> + */
> +TEST_F(liveupdate_device, get_session_name_max_length)
> +{
> + char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH] = {};
> + char long_name[LIVEUPDATE_SESSION_NAME_LENGTH];
> + int session_fd;
> +
> + memset(long_name, 'A', sizeof(long_name) - 1);
> + long_name[sizeof(long_name) - 1] = '\0';
> +
> + 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 = create_session(self->fd1, long_name);
> + ASSERT_GE(session_fd, 0);
> +
> + ASSERT_EQ(get_session_name(session_fd, name_buf, sizeof(name_buf)), 0);
> + ASSERT_STREQ(name_buf, long_name);
> +
> + ASSERT_EQ(close(session_fd), 0);
> +}
> +
> +/*
> + * Test Case: Create Session with No Null Termination
> + *
> + * Verifies that filling the entire 64-byte name field with non-null characters
> + * (no '\0' terminator) is handled safely by the kernel. The kernel's strscpy
> + * truncates to 63 characters, which we verify via get_session_name.
[...]
> + */
> +TEST_F(liveupdate_device, create_session_no_null_termination)
> +{
> + struct liveupdate_ioctl_create_session args = {};
> + char expected_name[LIVEUPDATE_SESSION_NAME_LENGTH];
> + char name_buf[LIVEUPDATE_SESSION_NAME_LENGTH] = {};
> + int session_fd;
> +
> + 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);
> +
> + /* Fill entire name field with 'X', no null terminator */
> + args.size = sizeof(args);
> + memset(args.name, 'X', sizeof(args.name));
> +
> + ASSERT_EQ(ioctl(self->fd1, LIVEUPDATE_IOCTL_CREATE_SESSION, &args), 0);
> + session_fd = args.fd;
> + ASSERT_GE(session_fd, 0);
> +
> + /* Kernel should have truncated to 63 chars + '\0' */
> + memset(expected_name, 'X', sizeof(expected_name) - 1);
> + expected_name[sizeof(expected_name) - 1] = '\0';
> +
> + ASSERT_EQ(get_session_name(session_fd, name_buf, sizeof(name_buf)), 0);
> + ASSERT_STREQ(name_buf, expected_name);
> +
> + ASSERT_EQ(close(session_fd), 0);
> +}
> +
> +/*
> + * Test Case: Create Session with Empty Name
> + *
> + * Verifies that creating a session with an empty string name succeeds,
> + * and that creating a second session with the same empty name fails
> + * with EEXIST.
> + */
For the two cases mentioned above, we should implement a fix in the
kernel:
In luo_session_create(), we should verify that the name is at least 1
character long and at most LIVEUPDATE_SESSION_NAME_LENGTH - 1.
size_t len = strnlen(name, LIVEUPDATE_SESSION_NAME_LENGTH);
if (!len || len > LIVEUPDATE_SESSION_NAME_LENGTH - 1)
return -EINVAL;
This change should be submitted as a separate patch in your series.
Additionally, please include a cover letter in the next version
explaining the overall series. Once the cover letter is included, you
can remove the individual patch versions from the stat areas.
Pasha
More information about the kexec
mailing list