Message ID | 5b2a65fa61ea2eb897a9a79827ad7b5f0a8e61cd.1608115761.git.viresh.kumar@linaro.org |
---|---|
State | Changes Requested |
Headers | show |
Series | [1/2] syscalls: init_module: Add tests | expand |
Hi! > diff --git a/testcases/kernel/syscalls/init_module/dummy_mod.c b/testcases/kernel/syscalls/init_module/dummy_mod.c > new file mode 100644 > index 000000000000..7c0b7a06aaa4 > --- /dev/null > +++ b/testcases/kernel/syscalls/init_module/dummy_mod.c > @@ -0,0 +1,43 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org> > + */ > + > +/*\ > + * [DESCRIPTION] > + * > + * Dummy test module. > + * > + * [ALGORITHM] > + * > + * The module accepts a single argument named "status" and it fails > + * initialization if the status is set to "invalid". > +\*/ This is pointless since the source is not test (does not define the tst_test structure) it will be ignored by the docparser. > +#include <linux/module.h> > +#include <linux/init.h> > +#include <linux/proc_fs.h> > +#include <linux/kernel.h> > + > +static char status[20]; > +module_param_string(status, status, 20, 0444); > + > +static int dummy_init(void) > +{ > + struct proc_dir_entry *proc_dummy; > + > + if (!strcmp(status, "invalid")) > + return -EINVAL; > + > + proc_dummy = proc_mkdir("dummy", 0); > + return 0; > +} > +module_init(dummy_init); > + > +static void dummy_exit(void) > +{ > + remove_proc_entry("dummy", 0); > +} > +module_exit(dummy_exit); > + > +MODULE_LICENSE("GPL"); Also I guess that the module file name should be prefixed by the syscall name, otherwise it will be overwritten on 'make install' since we install all test binaries into a single directory. > diff --git a/testcases/kernel/syscalls/init_module/init_module01.c b/testcases/kernel/syscalls/init_module/init_module01.c > new file mode 100644 > index 000000000000..9e8b03553a11 > --- /dev/null > +++ b/testcases/kernel/syscalls/init_module/init_module01.c > @@ -0,0 +1,59 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org> > + */ > + > +/*\ > + * [DESCRIPTION] > + * > + * Basic init_module() tests. > + * > + * [ALGORITHM] > + * > + * Inserts a simple module after opening and mmaping the module file. > +\*/ > + > +#include <errno.h> > +#include "lapi/init_module.h" > +#include "old_module.h" The old headers should not be used in the new library. So that should be done here is to export the fucntion to a new library properly by: Renaming the function the the tst_module.c so that the functions ends with under score, e.g. tst_module_unload() -> tst_module_unload_(). The old_module.h header will then include static inline functions that would just pass all the arguments to the functions eg. static inline void tst_module_unload(void (cleanup_fn)(void), const char *mod_name) { tst_module_unload_(cleanup_fn, mod_name); } and the new library will omit the cleanup argument as: static inline void tst_module_unload(const char *mod_name) { tst_module_unload(NULL, mod_name); } Another alternative is to port all the 8 tescases that call the tst_module* functions and port the tst_module.c to new library as well. > +#define MODULE_NAME "dummy_mod.ko" > + > +static struct stat sb; > +static void *buf; > + > +static void setup(void) > +{ > + int fd; > + > + fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC); > + SAFE_FSTAT(fd, &sb); > + buf = SAFE_MMAP(0, sb.st_size, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0); > + SAFE_CLOSE(fd); > +} > + > +static void run(void) > +{ > + TEST(init_module(buf, sb.st_size, "status=valid")); > + if (TST_RET == -1) { > + tst_res(TFAIL | TTERRNO, "init_module() failed for %s", > + MODULE_NAME); > + return; > + } TST_EXP_PASS() ? > + tst_module_unload(NULL, MODULE_NAME); > + > + tst_res(TPASS, "init_module() passed"); > +} > + > +static void cleanup(void) > +{ > + munmap(buf, sb.st_size); > +} > + > +static struct tst_test test = { > + .test_all = run, > + .setup = setup, > + .cleanup = cleanup, > + .needs_root = 1, > +}; > diff --git a/testcases/kernel/syscalls/init_module/init_module02.c b/testcases/kernel/syscalls/init_module/init_module02.c > new file mode 100644 > index 000000000000..d93c5cec856b > --- /dev/null > +++ b/testcases/kernel/syscalls/init_module/init_module02.c > @@ -0,0 +1,115 @@ > +// SPDX-License-Identifier: GPL-2.0-or-later > +/* > + * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org> > + */ > + > +/*\ > + * [DESCRIPTION] > + * > + * Basic init_module() failure tests. > + * > + * [ALGORITHM] > + * > + * Tests various failure scenarios for init_module(). > +\*/ > + > +#include <linux/capability.h> > +#include <errno.h> > +#include "lapi/init_module.h" > +#include "old_module.h" > +#include "tst_capability.h" > + > +#define MODULE_NAME "dummy_mod.ko" > + > +static unsigned long size, zero_size; > +static void *buf, *faulty_buf, *null_buf; > + > +static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); > +static struct tst_cap cap_drop = TST_CAP(TST_CAP_DROP, CAP_SYS_MODULE); > + > +static struct tcase { > + const char *name; > + void **buf; > + unsigned long *size; > + const char *param; > + int cap; > + int exp_errno; > +} tcases[] = { > + {"NULL-buffer", &null_buf, &size, "", 0, EFAULT}, > + {"faulty-buffer", &faulty_buf, &size, "", 0, EFAULT}, > + {"null-param", &buf, &size, NULL, 0, EFAULT}, > + {"zero-size", &buf, &zero_size, "", 0, ENOEXEC}, > + {"invalid_param", &buf, &size, "status=invalid", 0, EINVAL}, > + {"no-perm", &buf, &size, "", 1, EPERM}, > + {"module-exists", &buf, &size, "", 0, EEXIST}, > +}; > + > +static void setup(void) > +{ > + struct stat sb; > + int fd; > + > + fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC); > + SAFE_FSTAT(fd, &sb); > + size = sb.st_size; > + buf = SAFE_MMAP(0, size, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0); > + SAFE_CLOSE(fd); > + > + faulty_buf = tst_get_bad_addr(NULL); > +} > + > +static void run(unsigned int n) > +{ > + struct tcase *tc = &tcases[n]; > + > + if (tc->cap) > + tst_cap_action(&cap_drop); > + > + TEST(init_module(*tc->buf, *tc->size, tc->param)); > + > + /* Insert module twice */ > + if (tc->exp_errno == EEXIST) { > + if (TST_RET == -1) { > + tst_res(TFAIL | TTERRNO, > + "%s: init_module() failed unexpectedly", > + tc->name); > + return; > + } > + > + TEST(init_module(*tc->buf, *tc->size, tc->param)); > + tst_module_unload(NULL, MODULE_NAME); > + } > + > + if (tc->cap) > + tst_cap_action(&cap_req); > + > + if (TST_RET != -1) { > + tst_module_unload(NULL, MODULE_NAME); > + tst_res(TFAIL, "%s: init_module() passed unexpectedly", > + tc->name); > + return; > + } > + > + if (tc->exp_errno != TST_ERR) { > + tst_res(TFAIL | TTERRNO, > + "%s: init_module() should fail with %s", tc->name, > + tst_strerrno(tc->exp_errno)); > + return; > + } > + > + tst_res(TPASS | TTERRNO, "%s: init_module() failed as expected", > + tc->name); > +} > + > +static void cleanup(void) > +{ > + munmap(buf, size); > +} > + > +static struct tst_test test = { > + .test = run, > + .tcnt = ARRAY_SIZE(tcases), > + .setup = setup, > + .cleanup = cleanup, > + .needs_root = 1, > +}; > -- > 2.25.0.rc1.19.g042ed3e048af >
diff --git a/configure.ac b/configure.ac index 06be1c09417a..9840d99525fb 100644 --- a/configure.ac +++ b/configure.ac @@ -89,6 +89,7 @@ AC_CHECK_FUNCS_ONCE([ \ getauxval \ getdents \ getdents64 \ + init_module \ io_pgetevents \ io_uring_setup \ io_uring_register \ diff --git a/include/lapi/init_module.h b/include/lapi/init_module.h new file mode 100644 index 000000000000..ad556aec4aaa --- /dev/null +++ b/include/lapi/init_module.h @@ -0,0 +1,21 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Linaro Limited. All rights reserved. + * Author: Viresh Kumar <viresh.kumar@linaro.org> + */ + +#ifndef INIT_MODULE_H__ +#define INIT_MODULE_H__ + +#include "config.h" +#include "lapi/syscalls.h" +#include "tst_test.h" + +#ifndef HAVE_INIT_MODULE +static inline int init_module(void *module_image, unsigned long len, + const char *param_values) +{ + return tst_syscall(__NR_init_module, module_image, len, param_values); +} +#endif +#endif /* INIT_MODULE_H__ */ diff --git a/runtest/syscalls b/runtest/syscalls index 9c328697b4a3..28174dddd716 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -517,6 +517,9 @@ getxattr03 getxattr03 getxattr04 getxattr04 getxattr05 getxattr05 +init_module01 init_module01 +init_module02 init_module02 + #Needs tty device. #ioctl01 ioctl01 -D /dev/tty0 #ioctl02 ioctl02 -D /dev/tty0 diff --git a/testcases/kernel/syscalls/init_module/.gitignore b/testcases/kernel/syscalls/init_module/.gitignore new file mode 100644 index 000000000000..91e8ab971ccd --- /dev/null +++ b/testcases/kernel/syscalls/init_module/.gitignore @@ -0,0 +1,3 @@ +/init_module01 +/init_module02 +/dummy_mod.ko diff --git a/testcases/kernel/syscalls/init_module/Makefile b/testcases/kernel/syscalls/init_module/Makefile new file mode 100644 index 000000000000..ec40fb55c8fc --- /dev/null +++ b/testcases/kernel/syscalls/init_module/Makefile @@ -0,0 +1,21 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +ifneq ($(KERNELRELEASE),) + +obj-m := dummy_mod.o + +else + +top_srcdir ?= ../../../.. + +include $(top_srcdir)/include/mk/testcases.mk + +REQ_VERSION_MAJOR := 2 +REQ_VERSION_PATCH := 6 + +MAKE_TARGETS := init_module01 init_module02 dummy_mod.ko + +include $(top_srcdir)/include/mk/module.mk +include $(top_srcdir)/include/mk/generic_leaf_target.mk + +endif diff --git a/testcases/kernel/syscalls/init_module/dummy_mod.c b/testcases/kernel/syscalls/init_module/dummy_mod.c new file mode 100644 index 000000000000..7c0b7a06aaa4 --- /dev/null +++ b/testcases/kernel/syscalls/init_module/dummy_mod.c @@ -0,0 +1,43 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org> + */ + +/*\ + * [DESCRIPTION] + * + * Dummy test module. + * + * [ALGORITHM] + * + * The module accepts a single argument named "status" and it fails + * initialization if the status is set to "invalid". +\*/ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/proc_fs.h> +#include <linux/kernel.h> + +static char status[20]; +module_param_string(status, status, 20, 0444); + +static int dummy_init(void) +{ + struct proc_dir_entry *proc_dummy; + + if (!strcmp(status, "invalid")) + return -EINVAL; + + proc_dummy = proc_mkdir("dummy", 0); + return 0; +} +module_init(dummy_init); + +static void dummy_exit(void) +{ + remove_proc_entry("dummy", 0); +} +module_exit(dummy_exit); + +MODULE_LICENSE("GPL"); diff --git a/testcases/kernel/syscalls/init_module/init_module01.c b/testcases/kernel/syscalls/init_module/init_module01.c new file mode 100644 index 000000000000..9e8b03553a11 --- /dev/null +++ b/testcases/kernel/syscalls/init_module/init_module01.c @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org> + */ + +/*\ + * [DESCRIPTION] + * + * Basic init_module() tests. + * + * [ALGORITHM] + * + * Inserts a simple module after opening and mmaping the module file. +\*/ + +#include <errno.h> +#include "lapi/init_module.h" +#include "old_module.h" + +#define MODULE_NAME "dummy_mod.ko" + +static struct stat sb; +static void *buf; + +static void setup(void) +{ + int fd; + + fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC); + SAFE_FSTAT(fd, &sb); + buf = SAFE_MMAP(0, sb.st_size, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0); + SAFE_CLOSE(fd); +} + +static void run(void) +{ + TEST(init_module(buf, sb.st_size, "status=valid")); + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, "init_module() failed for %s", + MODULE_NAME); + return; + } + + tst_module_unload(NULL, MODULE_NAME); + + tst_res(TPASS, "init_module() passed"); +} + +static void cleanup(void) +{ + munmap(buf, sb.st_size); +} + +static struct tst_test test = { + .test_all = run, + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, +}; diff --git a/testcases/kernel/syscalls/init_module/init_module02.c b/testcases/kernel/syscalls/init_module/init_module02.c new file mode 100644 index 000000000000..d93c5cec856b --- /dev/null +++ b/testcases/kernel/syscalls/init_module/init_module02.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2020 Viresh Kumar <viresh.kumar@linaro.org> + */ + +/*\ + * [DESCRIPTION] + * + * Basic init_module() failure tests. + * + * [ALGORITHM] + * + * Tests various failure scenarios for init_module(). +\*/ + +#include <linux/capability.h> +#include <errno.h> +#include "lapi/init_module.h" +#include "old_module.h" +#include "tst_capability.h" + +#define MODULE_NAME "dummy_mod.ko" + +static unsigned long size, zero_size; +static void *buf, *faulty_buf, *null_buf; + +static struct tst_cap cap_req = TST_CAP(TST_CAP_REQ, CAP_SYS_MODULE); +static struct tst_cap cap_drop = TST_CAP(TST_CAP_DROP, CAP_SYS_MODULE); + +static struct tcase { + const char *name; + void **buf; + unsigned long *size; + const char *param; + int cap; + int exp_errno; +} tcases[] = { + {"NULL-buffer", &null_buf, &size, "", 0, EFAULT}, + {"faulty-buffer", &faulty_buf, &size, "", 0, EFAULT}, + {"null-param", &buf, &size, NULL, 0, EFAULT}, + {"zero-size", &buf, &zero_size, "", 0, ENOEXEC}, + {"invalid_param", &buf, &size, "status=invalid", 0, EINVAL}, + {"no-perm", &buf, &size, "", 1, EPERM}, + {"module-exists", &buf, &size, "", 0, EEXIST}, +}; + +static void setup(void) +{ + struct stat sb; + int fd; + + fd = SAFE_OPEN(MODULE_NAME, O_RDONLY|O_CLOEXEC); + SAFE_FSTAT(fd, &sb); + size = sb.st_size; + buf = SAFE_MMAP(0, size, PROT_READ|PROT_EXEC, MAP_PRIVATE, fd, 0); + SAFE_CLOSE(fd); + + faulty_buf = tst_get_bad_addr(NULL); +} + +static void run(unsigned int n) +{ + struct tcase *tc = &tcases[n]; + + if (tc->cap) + tst_cap_action(&cap_drop); + + TEST(init_module(*tc->buf, *tc->size, tc->param)); + + /* Insert module twice */ + if (tc->exp_errno == EEXIST) { + if (TST_RET == -1) { + tst_res(TFAIL | TTERRNO, + "%s: init_module() failed unexpectedly", + tc->name); + return; + } + + TEST(init_module(*tc->buf, *tc->size, tc->param)); + tst_module_unload(NULL, MODULE_NAME); + } + + if (tc->cap) + tst_cap_action(&cap_req); + + if (TST_RET != -1) { + tst_module_unload(NULL, MODULE_NAME); + tst_res(TFAIL, "%s: init_module() passed unexpectedly", + tc->name); + return; + } + + if (tc->exp_errno != TST_ERR) { + tst_res(TFAIL | TTERRNO, + "%s: init_module() should fail with %s", tc->name, + tst_strerrno(tc->exp_errno)); + return; + } + + tst_res(TPASS | TTERRNO, "%s: init_module() failed as expected", + tc->name); +} + +static void cleanup(void) +{ + munmap(buf, size); +} + +static struct tst_test test = { + .test = run, + .tcnt = ARRAY_SIZE(tcases), + .setup = setup, + .cleanup = cleanup, + .needs_root = 1, +};
This patch adds success and failure tests for init_module() syscall. Signed-off-by: Viresh Kumar <viresh.kumar@linaro.org> --- configure.ac | 1 + include/lapi/init_module.h | 21 ++++ runtest/syscalls | 3 + .../kernel/syscalls/init_module/.gitignore | 3 + .../kernel/syscalls/init_module/Makefile | 21 ++++ .../kernel/syscalls/init_module/dummy_mod.c | 43 +++++++ .../syscalls/init_module/init_module01.c | 59 +++++++++ .../syscalls/init_module/init_module02.c | 115 ++++++++++++++++++ 8 files changed, 266 insertions(+) create mode 100644 include/lapi/init_module.h create mode 100644 testcases/kernel/syscalls/init_module/.gitignore create mode 100644 testcases/kernel/syscalls/init_module/Makefile create mode 100644 testcases/kernel/syscalls/init_module/dummy_mod.c create mode 100644 testcases/kernel/syscalls/init_module/init_module01.c create mode 100644 testcases/kernel/syscalls/init_module/init_module02.c