Skip to content

Commit

Permalink
lkl: add a dlmopen testcase
Browse files Browse the repository at this point in the history
This commit add a testcase when LKL is loaded via dlmopen(3) function
call.  In this situation, the thread specific data which LKL uses
behaves wrong and cause an unconditional memory access.

This test should detect this case.

note 230614: the test hungs at this moment on the multiple
pthread_exit(), which is due to a lock handling on load of libgcc_s.so.
Still investigating what's going on.  If we replace dlmopen with dlopen,
everything goes fine..

Signed-off-by: Hajime Tazaki <[email protected]>
  • Loading branch information
thehajime committed Jun 27, 2023
1 parent 88060dc commit 4d8c80a
Show file tree
Hide file tree
Showing 4 changed files with 146 additions and 0 deletions.
1 change: 1 addition & 0 deletions tools/lkl/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ tests/net-test
tests/disk
tests/disk-vfio-pci
tests/config
tests/test-dlmopen
Makefile.conf
include/lkl_autoconf.h
include/kernel_config.h
Expand Down
4 changes: 4 additions & 0 deletions tools/lkl/Targets
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ progs-y += tests/disk
progs-y += tests/disk-vfio-pci
progs-y += tests/net-test
progs-y += tests/config
ifneq ($(LKL_HOST_CONFIG_BSD),y)
progs-y += tests/test-dlmopen
LDLIBS_tests/test-dlmopen-$(LKL_HOST_CONFIG_POSIX) += -ldl
endif

# LKL fuzzers
fuzzers-y += fuzzers/hid/hid-fuzzer
Expand Down
1 change: 1 addition & 0 deletions tools/lkl/tests/Build
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ disk-y += disk.o cla.o test.o
disk-vfio-pci-y += disk-vfio-pci.o cla.o test.o
net-test-y += net-test.o cla.o test.o
config-y += config.o test.o
test-dlmopen-y += test-dlmopen.o test.o
140 changes: 140 additions & 0 deletions tools/lkl/tests/test-dlmopen.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
// SPDX-License-Identifier: GPL-2.0

/* if dlemopen is not implemented, skip test */
#if defined(__x86_64__) && defined(__linux__)
#define _GNU_SOURCE
#include <string.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <lkl.h>
#include <lkl_host.h>
#include <lkl_config.h>

#include "test.h"

#define CMD_LINE "mem=16M loglevel=8"

/* glibc (may) only supports dlmopen(3) */
#ifndef LM_ID_NEWLM
#define NO_DLMOPEN_LINUX 1
#else
#define NO_DLMOPEN_LINUX 0
#endif

static int lkl_test_dlmopen(void)
{
void *handle;
long ret;
char *filename = "liblkl.so";
long params[6] = {0};
int (*fn_init)(struct lkl_host_operations *ops);
int (*fn_start)(char *fmt, ...);
long (*fn_syscall)(long no, long *params);
long (*fn_sys_halt)(void);
void (*fn_tls_mode)(void);
struct lkl_host_operations *lkl_host_ops;

/* XXX: if the dlmopen below is dlopen, everything is fine
* and can shutdown this test program.
*/
// handle = dlopen(filename, RTLD_NOW | RTLD_LOCAL);
handle = dlmopen(LM_ID_NEWLM, filename, RTLD_NOW | RTLD_LOCAL);
if (!handle) {
lkl_test_logf("%s: dlmopen failed, %s\n", __func__, dlerror());
return TEST_FAILURE;
}

fn_init = dlsym(handle, "lkl_init");
if (!fn_init) {
lkl_test_logf("%s: dlsym failed, %s\n", __func__, dlerror());
return TEST_FAILURE;
}

lkl_host_ops = dlsym(handle, "lkl_host_ops");
if (!lkl_host_ops) {
lkl_test_logf("%s: dlsym failed, %s\n", __func__, dlerror());
return TEST_FAILURE;
}

fn_start = dlsym(handle, "lkl_start_kernel");
if (!fn_start) {
lkl_test_logf("%s: dlsym failed, %s\n", __func__, dlerror());
return TEST_FAILURE;
}

fn_syscall = dlsym(handle, "lkl_syscall");
if (!fn_syscall) {
lkl_test_logf("%s: dlsym failed, %s\n", __func__, dlerror());
return TEST_FAILURE;
}

fn_sys_halt = dlsym(handle, "lkl_sys_halt");
if (!fn_sys_halt) {
lkl_test_logf("%s: dlsym failed, %s\n", __func__, dlerror());
return TEST_FAILURE;
}

fn_tls_mode = dlsym(handle, "lkl_change_tls_mode");
if (!fn_tls_mode) {
lkl_test_logf("%s: dlsym failed, %s\n", __func__, dlerror());
return TEST_FAILURE;
}

/* start calling resolved symbols */
// lkl_host_ops->print = lkl_test_log;
fn_tls_mode();
fn_init(lkl_host_ops);
ret = fn_start(CMD_LINE);
if (ret != 0) {
lkl_test_logf("lkl_start_kernel() = %ld %s\n",
ret, ret < 0 ? lkl_strerror(ret) : "");
return TEST_FAILURE;
}

ret = fn_syscall(__lkl__NR_getpid, params);
lkl_test_logf("getpid() = %ld\n", ret);
if (ret != 1) {
lkl_test_logf("getpid() = %ld %s\n", ret, ret < 0 ? lkl_strerror(ret) : "");
return TEST_FAILURE;
}

ret = fn_sys_halt();
if (ret != 0) {
lkl_test_logf("halt() = %ld %s\n", ret, ret < 0 ? lkl_strerror(ret) : "");
return TEST_FAILURE;
}

// dlclose(handle);
return ret == 0 ? TEST_SUCCESS : TEST_FAILURE;
}

struct lkl_test tests[] = {
LKL_TEST(dlmopen),
};

int main(int argc, const char **argv)
{
int ret;

if (NO_DLMOPEN_LINUX) {
lkl_test_logf("no dlmopen support\n");
return TEST_SKIP;
}

ret = lkl_test_run(tests, sizeof(tests)/sizeof(struct lkl_test),
"dlmopen");

lkl_cleanup();

return ret;
}

#else
#include "test.h"

int main(int argc, const char **argv)
{
lkl_test_logf("no x86_64 arch supported\n");
return TEST_SKIP;
}
#endif /* defined (__x86_64__) && defined (__linux__) */

0 comments on commit 4d8c80a

Please sign in to comment.