Message ID | 20230421174259.2458-12-casey@schaufler-ca.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | Paul Moore |
Headers | show |
Series | LSM: Three basic syscalls | expand |
On Fri, Apr 21, 2023 at 10:42:59AM -0700, Casey Schaufler wrote: > Add selftests for the three system calls supporting the LSM > infrastructure. Yay tests! With nits below fixed: Reviewed-by: Kees Cook <keescook@chromium.org> > > Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> > --- > tools/testing/selftests/Makefile | 1 + > tools/testing/selftests/lsm/Makefile | 12 + > tools/testing/selftests/lsm/config | 2 + > .../selftests/lsm/lsm_get_self_attr_test.c | 267 ++++++++++++++++++ > .../selftests/lsm/lsm_list_modules_test.c | 149 ++++++++++ > .../selftests/lsm/lsm_set_self_attr_test.c | 70 +++++ > 6 files changed, 501 insertions(+) > create mode 100644 tools/testing/selftests/lsm/Makefile > create mode 100644 tools/testing/selftests/lsm/config > create mode 100644 tools/testing/selftests/lsm/lsm_get_self_attr_test.c > create mode 100644 tools/testing/selftests/lsm/lsm_list_modules_test.c > create mode 100644 tools/testing/selftests/lsm/lsm_set_self_attr_test.c > > diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile > index 13a6837a0c6b..b18d133a1141 100644 > --- a/tools/testing/selftests/Makefile > +++ b/tools/testing/selftests/Makefile > @@ -38,6 +38,7 @@ TARGETS += landlock > TARGETS += lib > TARGETS += livepatch > TARGETS += lkdtm > +TARGETS += lsm > TARGETS += membarrier > TARGETS += memfd > TARGETS += memory-hotplug > diff --git a/tools/testing/selftests/lsm/Makefile b/tools/testing/selftests/lsm/Makefile > new file mode 100644 > index 000000000000..f39a75212b78 > --- /dev/null > +++ b/tools/testing/selftests/lsm/Makefile > @@ -0,0 +1,12 @@ > +# SPDX-License-Identifier: GPL-2.0 > +# > +# First run: make -C ../../../.. headers_install > + > +CFLAGS += -Wall -O2 $(KHDR_INCLUDES) > + > +TEST_GEN_PROGS := lsm_get_self_attr_test lsm_list_modules_test \ > + lsm_set_self_attr_test > + > +include ../lib.mk > + > +$(TEST_GEN_PROGS): > diff --git a/tools/testing/selftests/lsm/config b/tools/testing/selftests/lsm/config > new file mode 100644 > index 000000000000..afb887715f64 > --- /dev/null > +++ b/tools/testing/selftests/lsm/config > @@ -0,0 +1,2 @@ > +CONFIG_SYSFS=y > +CONFIG_SECURITY=y > diff --git a/tools/testing/selftests/lsm/lsm_get_self_attr_test.c b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c > new file mode 100644 > index 000000000000..71c2b1a8a44e > --- /dev/null > +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c > @@ -0,0 +1,267 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Linux Security Module infrastructure tests > + * Tests for the lsm_get_self_attr system call > + * > + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> > + * Copyright © 2022 Intel Corporation > + */ > + > +#define _GNU_SOURCE > +#include <linux/lsm.h> > +#include <fcntl.h> > +#include <string.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <sys/types.h> > +#include "../kselftest_harness.h" > + > +#define PROCATTR "/proc/self/attr/" > + > +static int read_proc_attr(const char *attr, char *value, __kernel_size_t size) > +{ > + int fd; > + int len; > + char *path; > + > + len = strlen(PROCATTR) + strlen(attr) + 1; > + path = calloc(len, 1); > + if (path == NULL) > + return -1; > + sprintf(path, "%s%s", PROCATTR, attr); > + > + fd = open(path, O_RDONLY); > + free(path); > + > + if (fd < 0) > + return -1; > + len = read(fd, value, size); > + if (len <= 0) > + return -1; > +fprintf(stderr, "len=%d\n", len); Accidentally leftover debugging? > + close(fd); > + > + path = strchr(value, '\n'); > + if (path) > + *path = '\0'; > + > + return 0; > +} > + > +static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp) > +{ > + void *vp; > + > + vp = (void *)ctxp + sizeof(*ctxp) + ctxp->ctx_len; > + return (struct lsm_ctx *)vp; > +} > + > +TEST(size_null_lsm_get_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *ctx = calloc(page_size, 1); > + > + ASSERT_NE(NULL, ctx); > + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, > + NULL, 0)); > + ASSERT_EQ(EINVAL, errno); > + > + free(ctx); > +} > + > +TEST(ctx_null_lsm_get_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + __kernel_size_t size = page_size; > + > + ASSERT_NE(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, NULL, > + &size, 0)); > + ASSERT_NE(1, size); > +} > + > +TEST(size_too_small_lsm_get_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *ctx = calloc(page_size, 1); > + __kernel_size_t size = 1; > + > + ASSERT_NE(NULL, ctx); > + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, > + &size, 0)); > + ASSERT_EQ(E2BIG, errno); > + ASSERT_NE(1, size); > + > + free(ctx); > +} > + > +TEST(flags_zero_lsm_get_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *ctx = calloc(page_size, 1); > + __kernel_size_t size = page_size; > + > + ASSERT_NE(NULL, ctx); I would explicitly set errno to 0 before syscalls, just to sure. > + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, > + &size, 1)); > + ASSERT_EQ(EINVAL, errno); > + ASSERT_EQ(page_size, size); > + > + free(ctx); > +} > + > +TEST(flags_overset_lsm_get_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *ctx = calloc(page_size, 1); > + __kernel_size_t size = page_size; > + > + ASSERT_NE(NULL, ctx); e.g.: errno = 0; but repeated for all syscalls below... > + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, > + LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx, &size, 0)); > + ASSERT_EQ(EOPNOTSUPP, errno); > + > + free(ctx); > +} > + > +TEST(basic_lsm_get_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + __kernel_size_t size = page_size; > + struct lsm_ctx *ctx = calloc(page_size, 1); > + struct lsm_ctx *tctx = NULL; > + __u64 *syscall_lsms = calloc(page_size, 1); > + char *attr = calloc(page_size, 1); > + int cnt_current = 0; > + int cnt_exec = 0; > + int cnt_fscreate = 0; > + int cnt_keycreate = 0; > + int cnt_prev = 0; > + int cnt_sockcreate = 0; > + int lsmcount; > + int count; > + int i; > + > + ASSERT_NE(NULL, ctx); > + ASSERT_NE(NULL, syscall_lsms); > + > + lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0); > + ASSERT_LE(1, lsmcount); > + > + for (i = 0; i < lsmcount; i++) { > + switch (syscall_lsms[i]) { > + case LSM_ID_SELINUX: > + cnt_current++; > + cnt_exec++; > + cnt_fscreate++; > + cnt_keycreate++; > + cnt_prev++; > + cnt_sockcreate++; > + break; > + case LSM_ID_SMACK: > + cnt_current++; > + break; > + case LSM_ID_APPARMOR: > + cnt_current++; > + cnt_exec++; > + cnt_prev++; > + break; > + default: > + break; > + } > + } > + > + if (cnt_current) { > + size = page_size; > + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, > + &size, 0); > + ASSERT_EQ(cnt_current, count); > + tctx = ctx; > + ASSERT_EQ(0, read_proc_attr("current", attr, page_size)); > + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); > + for (i = 1; i < count; i++) { > + tctx = next_ctx(tctx); > + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); > + } > + } > + if (cnt_exec) { > + size = page_size; > + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_EXEC, ctx, > + &size, 0); > + ASSERT_GE(cnt_exec, count); > + if (count > 0) { > + tctx = ctx; > + if (read_proc_attr("exec", attr, page_size) == 0) > + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); > + } > + for (i = 1; i < count; i++) { > + tctx = next_ctx(tctx); > + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); > + } > + } > + if (cnt_fscreate) { > + size = page_size; > + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_FSCREATE, ctx, > + &size, 0); > + ASSERT_GE(cnt_fscreate, count); > + if (count > 0) { > + tctx = ctx; > + if (read_proc_attr("fscreate", attr, page_size) == 0) > + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); > + } > + for (i = 1; i < count; i++) { > + tctx = next_ctx(tctx); > + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); > + } > + } > + if (cnt_keycreate) { > + size = page_size; > + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_KEYCREATE, ctx, > + &size, 0); > + ASSERT_GE(cnt_keycreate, count); > + if (count > 0) { > + tctx = ctx; > + if (read_proc_attr("keycreate", attr, page_size) == 0) > + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); > + } > + for (i = 1; i < count; i++) { > + tctx = next_ctx(tctx); > + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); > + } > + } > + if (cnt_prev) { > + size = page_size; > + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_PREV, ctx, > + &size, 0); > + ASSERT_GE(cnt_prev, count); > + if (count > 0) { > + tctx = ctx; > + ASSERT_EQ(0, read_proc_attr("prev", attr, page_size)); > + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); > + for (i = 1; i < count; i++) { > + tctx = next_ctx(tctx); > + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); > + } > + } > + } > + if (cnt_sockcreate) { > + size = page_size; > + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_SOCKCREATE, > + ctx, &size, 0); > + ASSERT_GE(cnt_sockcreate, count); > + if (count > 0) { > + tctx = ctx; > + if (read_proc_attr("sockcreate", attr, page_size) == 0) > + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); > + } > + for (i = 1; i < count; i++) { > + tctx = next_ctx(tctx); > + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); > + } > + } > + > + free(ctx); > + free(attr); > + free(syscall_lsms); > +} > + > +TEST_HARNESS_MAIN > diff --git a/tools/testing/selftests/lsm/lsm_list_modules_test.c b/tools/testing/selftests/lsm/lsm_list_modules_test.c > new file mode 100644 > index 000000000000..3ec814002710 > --- /dev/null > +++ b/tools/testing/selftests/lsm/lsm_list_modules_test.c > @@ -0,0 +1,149 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Linux Security Module infrastructure tests > + * Tests for the lsm_list_modules system call > + * > + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> > + * Copyright © 2022 Intel Corporation > + */ > + > +#define _GNU_SOURCE > +#include <linux/lsm.h> > +#include <string.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <sys/types.h> > +#include "../kselftest_harness.h" > + > +static int read_sysfs_lsms(char *lsms, __kernel_size_t size) > +{ > + FILE *fp; > + > + fp = fopen("/sys/kernel/security/lsm", "r"); > + if (fp == NULL) > + return -1; > + if (fread(lsms, 1, size, fp) <= 0) > + return -1; > + fclose(fp); > + return 0; > +} > + > +TEST(size_null_lsm_list_modules) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *syscall_lsms = calloc(page_size, 1); > + > + ASSERT_NE(NULL, syscall_lsms); > + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, NULL, 0)); > + ASSERT_EQ(EFAULT, errno); > + > + free(syscall_lsms); > +} > + > +TEST(ids_null_lsm_list_modules) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + __kernel_size_t size = page_size; > + > + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, NULL, &size, 0)); > + ASSERT_EQ(EFAULT, errno); > + ASSERT_NE(1, size); > +} > + > +TEST(size_too_small_lsm_list_modules) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *syscall_lsms = calloc(page_size, 1); > + __kernel_size_t size = 1; > + > + ASSERT_NE(NULL, syscall_lsms); > + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0)); > + ASSERT_EQ(E2BIG, errno); > + ASSERT_NE(1, size); > + > + free(syscall_lsms); > +} > + > +TEST(flags_set_lsm_list_modules) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *syscall_lsms = calloc(page_size, 1); > + __kernel_size_t size = page_size; > + > + ASSERT_NE(NULL, syscall_lsms); > + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, &size, 7)); > + ASSERT_EQ(EINVAL, errno); > + ASSERT_EQ(page_size, size); > + > + free(syscall_lsms); > +} > + > +TEST(correct_lsm_list_modules) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + __kernel_size_t size = page_size; > + __u64 *syscall_lsms = calloc(page_size, 1); > + char *sysfs_lsms = calloc(page_size, 1); > + char *name; > + char *cp; > + int count; > + int i; > + > + ASSERT_NE(NULL, sysfs_lsms); > + ASSERT_NE(NULL, syscall_lsms); > + ASSERT_EQ(0, read_sysfs_lsms(sysfs_lsms, page_size)); > + > + count = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0); > + ASSERT_LE(1, count); > + cp = sysfs_lsms; > + for (i = 0; i < count; i++) { > + switch (syscall_lsms[i]) { > + case LSM_ID_CAPABILITY: > + name = "capability"; > + break; > + case LSM_ID_SELINUX: > + name = "selinux"; > + break; > + case LSM_ID_SMACK: > + name = "smack"; > + break; > + case LSM_ID_TOMOYO: > + name = "tomoyo"; > + break; > + case LSM_ID_IMA: > + name = "ima"; > + break; > + case LSM_ID_APPARMOR: > + name = "apparmor"; > + break; > + case LSM_ID_YAMA: > + name = "yama"; > + break; > + case LSM_ID_LOADPIN: > + name = "loadpin"; > + break; > + case LSM_ID_SAFESETID: > + name = "safesetid"; > + break; > + case LSM_ID_LOCKDOWN: > + name = "lockdown"; > + break; > + case LSM_ID_BPF: > + name = "bpf"; > + break; > + case LSM_ID_LANDLOCK: > + name = "landlock"; > + break; > + default: > + name = "INVALID"; > + break; > + } > + ASSERT_EQ(0, strncmp(cp, name, strlen(name))); > + cp += strlen(name) + 1; > + } > + > + free(sysfs_lsms); > + free(syscall_lsms); > +} > + > +TEST_HARNESS_MAIN > diff --git a/tools/testing/selftests/lsm/lsm_set_self_attr_test.c b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c > new file mode 100644 > index 000000000000..ca538a703168 > --- /dev/null > +++ b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c > @@ -0,0 +1,70 @@ > +// SPDX-License-Identifier: GPL-2.0 > +/* > + * Linux Security Module infrastructure tests > + * Tests for the lsm_set_self_attr system call > + * > + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> > + * Copyright © 2022 Intel Corporation > + */ > + > +#define _GNU_SOURCE > +#include <linux/lsm.h> > +#include <string.h> > +#include <stdio.h> > +#include <unistd.h> > +#include <sys/types.h> > +#include "../kselftest_harness.h" > + > +TEST(ctx_null_lsm_set_self_attr) > +{ > + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, NULL, > + sizeof(struct lsm_ctx), 0)); > +} > + > +TEST(size_too_small_lsm_set_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + struct lsm_ctx *ctx = calloc(page_size, 1); > + __kernel_size_t size = page_size; > + > + ASSERT_NE(NULL, ctx); > + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, > + &size, 0)); > + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, ctx, 1, > + 0)); > + > + free(ctx); > +} > + > +TEST(flags_zero_lsm_set_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *ctx = calloc(page_size, 1); > + __kernel_size_t size = page_size; > + > + ASSERT_NE(NULL, ctx); > + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, > + &size, 0)); > + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, ctx, > + size, 1)); > + > + free(ctx); > +} > + > +TEST(flags_overset_lsm_set_self_attr) > +{ > + const long page_size = sysconf(_SC_PAGESIZE); > + char *ctx = calloc(page_size, 1); > + __kernel_size_t size = page_size; > + struct lsm_ctx *tctx = (struct lsm_ctx *)ctx; > + > + ASSERT_NE(NULL, ctx); > + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, tctx, > + &size, 0)); > + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, > + LSM_ATTR_CURRENT | LSM_ATTR_PREV, tctx, size, 0)); > + > + free(ctx); > +} > + > +TEST_HARNESS_MAIN > -- > 2.39.2 >
On 4/21/2023 1:01 PM, Kees Cook wrote: > On Fri, Apr 21, 2023 at 10:42:59AM -0700, Casey Schaufler wrote: >> Add selftests for the three system calls supporting the LSM >> infrastructure. > Yay tests! > > With nits below fixed: > > Reviewed-by: Kees Cook <keescook@chromium.org> > >> Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> >> --- >> tools/testing/selftests/Makefile | 1 + >> tools/testing/selftests/lsm/Makefile | 12 + >> tools/testing/selftests/lsm/config | 2 + >> .../selftests/lsm/lsm_get_self_attr_test.c | 267 ++++++++++++++++++ >> .../selftests/lsm/lsm_list_modules_test.c | 149 ++++++++++ >> .../selftests/lsm/lsm_set_self_attr_test.c | 70 +++++ >> 6 files changed, 501 insertions(+) >> create mode 100644 tools/testing/selftests/lsm/Makefile >> create mode 100644 tools/testing/selftests/lsm/config >> create mode 100644 tools/testing/selftests/lsm/lsm_get_self_attr_test.c >> create mode 100644 tools/testing/selftests/lsm/lsm_list_modules_test.c >> create mode 100644 tools/testing/selftests/lsm/lsm_set_self_attr_test.c >> >> diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile >> index 13a6837a0c6b..b18d133a1141 100644 >> --- a/tools/testing/selftests/Makefile >> +++ b/tools/testing/selftests/Makefile >> @@ -38,6 +38,7 @@ TARGETS += landlock >> TARGETS += lib >> TARGETS += livepatch >> TARGETS += lkdtm >> +TARGETS += lsm >> TARGETS += membarrier >> TARGETS += memfd >> TARGETS += memory-hotplug >> diff --git a/tools/testing/selftests/lsm/Makefile b/tools/testing/selftests/lsm/Makefile >> new file mode 100644 >> index 000000000000..f39a75212b78 >> --- /dev/null >> +++ b/tools/testing/selftests/lsm/Makefile >> @@ -0,0 +1,12 @@ >> +# SPDX-License-Identifier: GPL-2.0 >> +# >> +# First run: make -C ../../../.. headers_install >> + >> +CFLAGS += -Wall -O2 $(KHDR_INCLUDES) >> + >> +TEST_GEN_PROGS := lsm_get_self_attr_test lsm_list_modules_test \ >> + lsm_set_self_attr_test >> + >> +include ../lib.mk >> + >> +$(TEST_GEN_PROGS): >> diff --git a/tools/testing/selftests/lsm/config b/tools/testing/selftests/lsm/config >> new file mode 100644 >> index 000000000000..afb887715f64 >> --- /dev/null >> +++ b/tools/testing/selftests/lsm/config >> @@ -0,0 +1,2 @@ >> +CONFIG_SYSFS=y >> +CONFIG_SECURITY=y >> diff --git a/tools/testing/selftests/lsm/lsm_get_self_attr_test.c b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c >> new file mode 100644 >> index 000000000000..71c2b1a8a44e >> --- /dev/null >> +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c >> @@ -0,0 +1,267 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Linux Security Module infrastructure tests >> + * Tests for the lsm_get_self_attr system call >> + * >> + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> >> + * Copyright © 2022 Intel Corporation >> + */ >> + >> +#define _GNU_SOURCE >> +#include <linux/lsm.h> >> +#include <fcntl.h> >> +#include <string.h> >> +#include <stdio.h> >> +#include <unistd.h> >> +#include <sys/types.h> >> +#include "../kselftest_harness.h" >> + >> +#define PROCATTR "/proc/self/attr/" >> + >> +static int read_proc_attr(const char *attr, char *value, __kernel_size_t size) >> +{ >> + int fd; >> + int len; >> + char *path; >> + >> + len = strlen(PROCATTR) + strlen(attr) + 1; >> + path = calloc(len, 1); >> + if (path == NULL) >> + return -1; >> + sprintf(path, "%s%s", PROCATTR, attr); >> + >> + fd = open(path, O_RDONLY); >> + free(path); >> + >> + if (fd < 0) >> + return -1; >> + len = read(fd, value, size); >> + if (len <= 0) >> + return -1; >> +fprintf(stderr, "len=%d\n", len); > Accidentally leftover debugging? Yup. >> + close(fd); >> + >> + path = strchr(value, '\n'); >> + if (path) >> + *path = '\0'; >> + >> + return 0; >> +} >> + >> +static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp) >> +{ >> + void *vp; >> + >> + vp = (void *)ctxp + sizeof(*ctxp) + ctxp->ctx_len; >> + return (struct lsm_ctx *)vp; >> +} >> + >> +TEST(size_null_lsm_get_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *ctx = calloc(page_size, 1); >> + >> + ASSERT_NE(NULL, ctx); >> + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, >> + NULL, 0)); >> + ASSERT_EQ(EINVAL, errno); >> + >> + free(ctx); >> +} >> + >> +TEST(ctx_null_lsm_get_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + __kernel_size_t size = page_size; >> + >> + ASSERT_NE(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, NULL, >> + &size, 0)); >> + ASSERT_NE(1, size); >> +} >> + >> +TEST(size_too_small_lsm_get_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *ctx = calloc(page_size, 1); >> + __kernel_size_t size = 1; >> + >> + ASSERT_NE(NULL, ctx); >> + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, >> + &size, 0)); >> + ASSERT_EQ(E2BIG, errno); >> + ASSERT_NE(1, size); >> + >> + free(ctx); >> +} >> + >> +TEST(flags_zero_lsm_get_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *ctx = calloc(page_size, 1); >> + __kernel_size_t size = page_size; >> + >> + ASSERT_NE(NULL, ctx); > I would explicitly set errno to 0 before syscalls, just to sure. Good idea for the cases where errno gets checked. >> + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, >> + &size, 1)); >> + ASSERT_EQ(EINVAL, errno); >> + ASSERT_EQ(page_size, size); >> + >> + free(ctx); >> +} >> + >> +TEST(flags_overset_lsm_get_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *ctx = calloc(page_size, 1); >> + __kernel_size_t size = page_size; >> + >> + ASSERT_NE(NULL, ctx); > e.g.: > errno = 0; > > but repeated for all syscalls below... > >> + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, >> + LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx, &size, 0)); >> + ASSERT_EQ(EOPNOTSUPP, errno); >> + >> + free(ctx); >> +} >> + >> +TEST(basic_lsm_get_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + __kernel_size_t size = page_size; >> + struct lsm_ctx *ctx = calloc(page_size, 1); >> + struct lsm_ctx *tctx = NULL; >> + __u64 *syscall_lsms = calloc(page_size, 1); >> + char *attr = calloc(page_size, 1); >> + int cnt_current = 0; >> + int cnt_exec = 0; >> + int cnt_fscreate = 0; >> + int cnt_keycreate = 0; >> + int cnt_prev = 0; >> + int cnt_sockcreate = 0; >> + int lsmcount; >> + int count; >> + int i; >> + >> + ASSERT_NE(NULL, ctx); >> + ASSERT_NE(NULL, syscall_lsms); >> + >> + lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0); >> + ASSERT_LE(1, lsmcount); >> + >> + for (i = 0; i < lsmcount; i++) { >> + switch (syscall_lsms[i]) { >> + case LSM_ID_SELINUX: >> + cnt_current++; >> + cnt_exec++; >> + cnt_fscreate++; >> + cnt_keycreate++; >> + cnt_prev++; >> + cnt_sockcreate++; >> + break; >> + case LSM_ID_SMACK: >> + cnt_current++; >> + break; >> + case LSM_ID_APPARMOR: >> + cnt_current++; >> + cnt_exec++; >> + cnt_prev++; >> + break; >> + default: >> + break; >> + } >> + } >> + >> + if (cnt_current) { >> + size = page_size; >> + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, >> + &size, 0); >> + ASSERT_EQ(cnt_current, count); >> + tctx = ctx; >> + ASSERT_EQ(0, read_proc_attr("current", attr, page_size)); >> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); >> + for (i = 1; i < count; i++) { >> + tctx = next_ctx(tctx); >> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + } >> + if (cnt_exec) { >> + size = page_size; >> + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_EXEC, ctx, >> + &size, 0); >> + ASSERT_GE(cnt_exec, count); >> + if (count > 0) { >> + tctx = ctx; >> + if (read_proc_attr("exec", attr, page_size) == 0) >> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + for (i = 1; i < count; i++) { >> + tctx = next_ctx(tctx); >> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + } >> + if (cnt_fscreate) { >> + size = page_size; >> + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_FSCREATE, ctx, >> + &size, 0); >> + ASSERT_GE(cnt_fscreate, count); >> + if (count > 0) { >> + tctx = ctx; >> + if (read_proc_attr("fscreate", attr, page_size) == 0) >> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + for (i = 1; i < count; i++) { >> + tctx = next_ctx(tctx); >> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + } >> + if (cnt_keycreate) { >> + size = page_size; >> + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_KEYCREATE, ctx, >> + &size, 0); >> + ASSERT_GE(cnt_keycreate, count); >> + if (count > 0) { >> + tctx = ctx; >> + if (read_proc_attr("keycreate", attr, page_size) == 0) >> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + for (i = 1; i < count; i++) { >> + tctx = next_ctx(tctx); >> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + } >> + if (cnt_prev) { >> + size = page_size; >> + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_PREV, ctx, >> + &size, 0); >> + ASSERT_GE(cnt_prev, count); >> + if (count > 0) { >> + tctx = ctx; >> + ASSERT_EQ(0, read_proc_attr("prev", attr, page_size)); >> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); >> + for (i = 1; i < count; i++) { >> + tctx = next_ctx(tctx); >> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + } >> + } >> + if (cnt_sockcreate) { >> + size = page_size; >> + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_SOCKCREATE, >> + ctx, &size, 0); >> + ASSERT_GE(cnt_sockcreate, count); >> + if (count > 0) { >> + tctx = ctx; >> + if (read_proc_attr("sockcreate", attr, page_size) == 0) >> + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + for (i = 1; i < count; i++) { >> + tctx = next_ctx(tctx); >> + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); >> + } >> + } >> + >> + free(ctx); >> + free(attr); >> + free(syscall_lsms); >> +} >> + >> +TEST_HARNESS_MAIN >> diff --git a/tools/testing/selftests/lsm/lsm_list_modules_test.c b/tools/testing/selftests/lsm/lsm_list_modules_test.c >> new file mode 100644 >> index 000000000000..3ec814002710 >> --- /dev/null >> +++ b/tools/testing/selftests/lsm/lsm_list_modules_test.c >> @@ -0,0 +1,149 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Linux Security Module infrastructure tests >> + * Tests for the lsm_list_modules system call >> + * >> + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> >> + * Copyright © 2022 Intel Corporation >> + */ >> + >> +#define _GNU_SOURCE >> +#include <linux/lsm.h> >> +#include <string.h> >> +#include <stdio.h> >> +#include <unistd.h> >> +#include <sys/types.h> >> +#include "../kselftest_harness.h" >> + >> +static int read_sysfs_lsms(char *lsms, __kernel_size_t size) >> +{ >> + FILE *fp; >> + >> + fp = fopen("/sys/kernel/security/lsm", "r"); >> + if (fp == NULL) >> + return -1; >> + if (fread(lsms, 1, size, fp) <= 0) >> + return -1; >> + fclose(fp); >> + return 0; >> +} >> + >> +TEST(size_null_lsm_list_modules) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *syscall_lsms = calloc(page_size, 1); >> + >> + ASSERT_NE(NULL, syscall_lsms); >> + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, NULL, 0)); >> + ASSERT_EQ(EFAULT, errno); >> + >> + free(syscall_lsms); >> +} >> + >> +TEST(ids_null_lsm_list_modules) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + __kernel_size_t size = page_size; >> + >> + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, NULL, &size, 0)); >> + ASSERT_EQ(EFAULT, errno); >> + ASSERT_NE(1, size); >> +} >> + >> +TEST(size_too_small_lsm_list_modules) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *syscall_lsms = calloc(page_size, 1); >> + __kernel_size_t size = 1; >> + >> + ASSERT_NE(NULL, syscall_lsms); >> + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0)); >> + ASSERT_EQ(E2BIG, errno); >> + ASSERT_NE(1, size); >> + >> + free(syscall_lsms); >> +} >> + >> +TEST(flags_set_lsm_list_modules) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *syscall_lsms = calloc(page_size, 1); >> + __kernel_size_t size = page_size; >> + >> + ASSERT_NE(NULL, syscall_lsms); >> + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, &size, 7)); >> + ASSERT_EQ(EINVAL, errno); >> + ASSERT_EQ(page_size, size); >> + >> + free(syscall_lsms); >> +} >> + >> +TEST(correct_lsm_list_modules) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + __kernel_size_t size = page_size; >> + __u64 *syscall_lsms = calloc(page_size, 1); >> + char *sysfs_lsms = calloc(page_size, 1); >> + char *name; >> + char *cp; >> + int count; >> + int i; >> + >> + ASSERT_NE(NULL, sysfs_lsms); >> + ASSERT_NE(NULL, syscall_lsms); >> + ASSERT_EQ(0, read_sysfs_lsms(sysfs_lsms, page_size)); >> + >> + count = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0); >> + ASSERT_LE(1, count); >> + cp = sysfs_lsms; >> + for (i = 0; i < count; i++) { >> + switch (syscall_lsms[i]) { >> + case LSM_ID_CAPABILITY: >> + name = "capability"; >> + break; >> + case LSM_ID_SELINUX: >> + name = "selinux"; >> + break; >> + case LSM_ID_SMACK: >> + name = "smack"; >> + break; >> + case LSM_ID_TOMOYO: >> + name = "tomoyo"; >> + break; >> + case LSM_ID_IMA: >> + name = "ima"; >> + break; >> + case LSM_ID_APPARMOR: >> + name = "apparmor"; >> + break; >> + case LSM_ID_YAMA: >> + name = "yama"; >> + break; >> + case LSM_ID_LOADPIN: >> + name = "loadpin"; >> + break; >> + case LSM_ID_SAFESETID: >> + name = "safesetid"; >> + break; >> + case LSM_ID_LOCKDOWN: >> + name = "lockdown"; >> + break; >> + case LSM_ID_BPF: >> + name = "bpf"; >> + break; >> + case LSM_ID_LANDLOCK: >> + name = "landlock"; >> + break; >> + default: >> + name = "INVALID"; >> + break; >> + } >> + ASSERT_EQ(0, strncmp(cp, name, strlen(name))); >> + cp += strlen(name) + 1; >> + } >> + >> + free(sysfs_lsms); >> + free(syscall_lsms); >> +} >> + >> +TEST_HARNESS_MAIN >> diff --git a/tools/testing/selftests/lsm/lsm_set_self_attr_test.c b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c >> new file mode 100644 >> index 000000000000..ca538a703168 >> --- /dev/null >> +++ b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c >> @@ -0,0 +1,70 @@ >> +// SPDX-License-Identifier: GPL-2.0 >> +/* >> + * Linux Security Module infrastructure tests >> + * Tests for the lsm_set_self_attr system call >> + * >> + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> >> + * Copyright © 2022 Intel Corporation >> + */ >> + >> +#define _GNU_SOURCE >> +#include <linux/lsm.h> >> +#include <string.h> >> +#include <stdio.h> >> +#include <unistd.h> >> +#include <sys/types.h> >> +#include "../kselftest_harness.h" >> + >> +TEST(ctx_null_lsm_set_self_attr) >> +{ >> + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, NULL, >> + sizeof(struct lsm_ctx), 0)); >> +} >> + >> +TEST(size_too_small_lsm_set_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + struct lsm_ctx *ctx = calloc(page_size, 1); >> + __kernel_size_t size = page_size; >> + >> + ASSERT_NE(NULL, ctx); >> + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, >> + &size, 0)); >> + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, ctx, 1, >> + 0)); >> + >> + free(ctx); >> +} >> + >> +TEST(flags_zero_lsm_set_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *ctx = calloc(page_size, 1); >> + __kernel_size_t size = page_size; >> + >> + ASSERT_NE(NULL, ctx); >> + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, >> + &size, 0)); >> + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, ctx, >> + size, 1)); >> + >> + free(ctx); >> +} >> + >> +TEST(flags_overset_lsm_set_self_attr) >> +{ >> + const long page_size = sysconf(_SC_PAGESIZE); >> + char *ctx = calloc(page_size, 1); >> + __kernel_size_t size = page_size; >> + struct lsm_ctx *tctx = (struct lsm_ctx *)ctx; >> + >> + ASSERT_NE(NULL, ctx); >> + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, tctx, >> + &size, 0)); >> + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, >> + LSM_ATTR_CURRENT | LSM_ATTR_PREV, tctx, size, 0)); >> + >> + free(ctx); >> +} >> + >> +TEST_HARNESS_MAIN >> -- >> 2.39.2 >>
diff --git a/tools/testing/selftests/Makefile b/tools/testing/selftests/Makefile index 13a6837a0c6b..b18d133a1141 100644 --- a/tools/testing/selftests/Makefile +++ b/tools/testing/selftests/Makefile @@ -38,6 +38,7 @@ TARGETS += landlock TARGETS += lib TARGETS += livepatch TARGETS += lkdtm +TARGETS += lsm TARGETS += membarrier TARGETS += memfd TARGETS += memory-hotplug diff --git a/tools/testing/selftests/lsm/Makefile b/tools/testing/selftests/lsm/Makefile new file mode 100644 index 000000000000..f39a75212b78 --- /dev/null +++ b/tools/testing/selftests/lsm/Makefile @@ -0,0 +1,12 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# First run: make -C ../../../.. headers_install + +CFLAGS += -Wall -O2 $(KHDR_INCLUDES) + +TEST_GEN_PROGS := lsm_get_self_attr_test lsm_list_modules_test \ + lsm_set_self_attr_test + +include ../lib.mk + +$(TEST_GEN_PROGS): diff --git a/tools/testing/selftests/lsm/config b/tools/testing/selftests/lsm/config new file mode 100644 index 000000000000..afb887715f64 --- /dev/null +++ b/tools/testing/selftests/lsm/config @@ -0,0 +1,2 @@ +CONFIG_SYSFS=y +CONFIG_SECURITY=y diff --git a/tools/testing/selftests/lsm/lsm_get_self_attr_test.c b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c new file mode 100644 index 000000000000..71c2b1a8a44e --- /dev/null +++ b/tools/testing/selftests/lsm/lsm_get_self_attr_test.c @@ -0,0 +1,267 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Linux Security Module infrastructure tests + * Tests for the lsm_get_self_attr system call + * + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> + * Copyright © 2022 Intel Corporation + */ + +#define _GNU_SOURCE +#include <linux/lsm.h> +#include <fcntl.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include "../kselftest_harness.h" + +#define PROCATTR "/proc/self/attr/" + +static int read_proc_attr(const char *attr, char *value, __kernel_size_t size) +{ + int fd; + int len; + char *path; + + len = strlen(PROCATTR) + strlen(attr) + 1; + path = calloc(len, 1); + if (path == NULL) + return -1; + sprintf(path, "%s%s", PROCATTR, attr); + + fd = open(path, O_RDONLY); + free(path); + + if (fd < 0) + return -1; + len = read(fd, value, size); + if (len <= 0) + return -1; +fprintf(stderr, "len=%d\n", len); + close(fd); + + path = strchr(value, '\n'); + if (path) + *path = '\0'; + + return 0; +} + +static struct lsm_ctx *next_ctx(struct lsm_ctx *ctxp) +{ + void *vp; + + vp = (void *)ctxp + sizeof(*ctxp) + ctxp->ctx_len; + return (struct lsm_ctx *)vp; +} + +TEST(size_null_lsm_get_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *ctx = calloc(page_size, 1); + + ASSERT_NE(NULL, ctx); + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, + NULL, 0)); + ASSERT_EQ(EINVAL, errno); + + free(ctx); +} + +TEST(ctx_null_lsm_get_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + __kernel_size_t size = page_size; + + ASSERT_NE(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, NULL, + &size, 0)); + ASSERT_NE(1, size); +} + +TEST(size_too_small_lsm_get_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *ctx = calloc(page_size, 1); + __kernel_size_t size = 1; + + ASSERT_NE(NULL, ctx); + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, + &size, 0)); + ASSERT_EQ(E2BIG, errno); + ASSERT_NE(1, size); + + free(ctx); +} + +TEST(flags_zero_lsm_get_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *ctx = calloc(page_size, 1); + __kernel_size_t size = page_size; + + ASSERT_NE(NULL, ctx); + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, + &size, 1)); + ASSERT_EQ(EINVAL, errno); + ASSERT_EQ(page_size, size); + + free(ctx); +} + +TEST(flags_overset_lsm_get_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *ctx = calloc(page_size, 1); + __kernel_size_t size = page_size; + + ASSERT_NE(NULL, ctx); + ASSERT_EQ(-1, syscall(__NR_lsm_get_self_attr, + LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx, &size, 0)); + ASSERT_EQ(EOPNOTSUPP, errno); + + free(ctx); +} + +TEST(basic_lsm_get_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + __kernel_size_t size = page_size; + struct lsm_ctx *ctx = calloc(page_size, 1); + struct lsm_ctx *tctx = NULL; + __u64 *syscall_lsms = calloc(page_size, 1); + char *attr = calloc(page_size, 1); + int cnt_current = 0; + int cnt_exec = 0; + int cnt_fscreate = 0; + int cnt_keycreate = 0; + int cnt_prev = 0; + int cnt_sockcreate = 0; + int lsmcount; + int count; + int i; + + ASSERT_NE(NULL, ctx); + ASSERT_NE(NULL, syscall_lsms); + + lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0); + ASSERT_LE(1, lsmcount); + + for (i = 0; i < lsmcount; i++) { + switch (syscall_lsms[i]) { + case LSM_ID_SELINUX: + cnt_current++; + cnt_exec++; + cnt_fscreate++; + cnt_keycreate++; + cnt_prev++; + cnt_sockcreate++; + break; + case LSM_ID_SMACK: + cnt_current++; + break; + case LSM_ID_APPARMOR: + cnt_current++; + cnt_exec++; + cnt_prev++; + break; + default: + break; + } + } + + if (cnt_current) { + size = page_size; + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, + &size, 0); + ASSERT_EQ(cnt_current, count); + tctx = ctx; + ASSERT_EQ(0, read_proc_attr("current", attr, page_size)); + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); + for (i = 1; i < count; i++) { + tctx = next_ctx(tctx); + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); + } + } + if (cnt_exec) { + size = page_size; + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_EXEC, ctx, + &size, 0); + ASSERT_GE(cnt_exec, count); + if (count > 0) { + tctx = ctx; + if (read_proc_attr("exec", attr, page_size) == 0) + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); + } + for (i = 1; i < count; i++) { + tctx = next_ctx(tctx); + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); + } + } + if (cnt_fscreate) { + size = page_size; + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_FSCREATE, ctx, + &size, 0); + ASSERT_GE(cnt_fscreate, count); + if (count > 0) { + tctx = ctx; + if (read_proc_attr("fscreate", attr, page_size) == 0) + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); + } + for (i = 1; i < count; i++) { + tctx = next_ctx(tctx); + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); + } + } + if (cnt_keycreate) { + size = page_size; + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_KEYCREATE, ctx, + &size, 0); + ASSERT_GE(cnt_keycreate, count); + if (count > 0) { + tctx = ctx; + if (read_proc_attr("keycreate", attr, page_size) == 0) + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); + } + for (i = 1; i < count; i++) { + tctx = next_ctx(tctx); + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); + } + } + if (cnt_prev) { + size = page_size; + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_PREV, ctx, + &size, 0); + ASSERT_GE(cnt_prev, count); + if (count > 0) { + tctx = ctx; + ASSERT_EQ(0, read_proc_attr("prev", attr, page_size)); + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); + for (i = 1; i < count; i++) { + tctx = next_ctx(tctx); + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); + } + } + } + if (cnt_sockcreate) { + size = page_size; + count = syscall(__NR_lsm_get_self_attr, LSM_ATTR_SOCKCREATE, + ctx, &size, 0); + ASSERT_GE(cnt_sockcreate, count); + if (count > 0) { + tctx = ctx; + if (read_proc_attr("sockcreate", attr, page_size) == 0) + ASSERT_EQ(0, strcmp((char *)tctx->ctx, attr)); + } + for (i = 1; i < count; i++) { + tctx = next_ctx(tctx); + ASSERT_NE(0, strcmp((char *)tctx->ctx, attr)); + } + } + + free(ctx); + free(attr); + free(syscall_lsms); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/lsm/lsm_list_modules_test.c b/tools/testing/selftests/lsm/lsm_list_modules_test.c new file mode 100644 index 000000000000..3ec814002710 --- /dev/null +++ b/tools/testing/selftests/lsm/lsm_list_modules_test.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Linux Security Module infrastructure tests + * Tests for the lsm_list_modules system call + * + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> + * Copyright © 2022 Intel Corporation + */ + +#define _GNU_SOURCE +#include <linux/lsm.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include "../kselftest_harness.h" + +static int read_sysfs_lsms(char *lsms, __kernel_size_t size) +{ + FILE *fp; + + fp = fopen("/sys/kernel/security/lsm", "r"); + if (fp == NULL) + return -1; + if (fread(lsms, 1, size, fp) <= 0) + return -1; + fclose(fp); + return 0; +} + +TEST(size_null_lsm_list_modules) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *syscall_lsms = calloc(page_size, 1); + + ASSERT_NE(NULL, syscall_lsms); + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, NULL, 0)); + ASSERT_EQ(EFAULT, errno); + + free(syscall_lsms); +} + +TEST(ids_null_lsm_list_modules) +{ + const long page_size = sysconf(_SC_PAGESIZE); + __kernel_size_t size = page_size; + + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, NULL, &size, 0)); + ASSERT_EQ(EFAULT, errno); + ASSERT_NE(1, size); +} + +TEST(size_too_small_lsm_list_modules) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *syscall_lsms = calloc(page_size, 1); + __kernel_size_t size = 1; + + ASSERT_NE(NULL, syscall_lsms); + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0)); + ASSERT_EQ(E2BIG, errno); + ASSERT_NE(1, size); + + free(syscall_lsms); +} + +TEST(flags_set_lsm_list_modules) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *syscall_lsms = calloc(page_size, 1); + __kernel_size_t size = page_size; + + ASSERT_NE(NULL, syscall_lsms); + ASSERT_EQ(-1, syscall(__NR_lsm_list_modules, syscall_lsms, &size, 7)); + ASSERT_EQ(EINVAL, errno); + ASSERT_EQ(page_size, size); + + free(syscall_lsms); +} + +TEST(correct_lsm_list_modules) +{ + const long page_size = sysconf(_SC_PAGESIZE); + __kernel_size_t size = page_size; + __u64 *syscall_lsms = calloc(page_size, 1); + char *sysfs_lsms = calloc(page_size, 1); + char *name; + char *cp; + int count; + int i; + + ASSERT_NE(NULL, sysfs_lsms); + ASSERT_NE(NULL, syscall_lsms); + ASSERT_EQ(0, read_sysfs_lsms(sysfs_lsms, page_size)); + + count = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0); + ASSERT_LE(1, count); + cp = sysfs_lsms; + for (i = 0; i < count; i++) { + switch (syscall_lsms[i]) { + case LSM_ID_CAPABILITY: + name = "capability"; + break; + case LSM_ID_SELINUX: + name = "selinux"; + break; + case LSM_ID_SMACK: + name = "smack"; + break; + case LSM_ID_TOMOYO: + name = "tomoyo"; + break; + case LSM_ID_IMA: + name = "ima"; + break; + case LSM_ID_APPARMOR: + name = "apparmor"; + break; + case LSM_ID_YAMA: + name = "yama"; + break; + case LSM_ID_LOADPIN: + name = "loadpin"; + break; + case LSM_ID_SAFESETID: + name = "safesetid"; + break; + case LSM_ID_LOCKDOWN: + name = "lockdown"; + break; + case LSM_ID_BPF: + name = "bpf"; + break; + case LSM_ID_LANDLOCK: + name = "landlock"; + break; + default: + name = "INVALID"; + break; + } + ASSERT_EQ(0, strncmp(cp, name, strlen(name))); + cp += strlen(name) + 1; + } + + free(sysfs_lsms); + free(syscall_lsms); +} + +TEST_HARNESS_MAIN diff --git a/tools/testing/selftests/lsm/lsm_set_self_attr_test.c b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c new file mode 100644 index 000000000000..ca538a703168 --- /dev/null +++ b/tools/testing/selftests/lsm/lsm_set_self_attr_test.c @@ -0,0 +1,70 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Linux Security Module infrastructure tests + * Tests for the lsm_set_self_attr system call + * + * Copyright © 2022 Casey Schaufler <casey@schaufler-ca.com> + * Copyright © 2022 Intel Corporation + */ + +#define _GNU_SOURCE +#include <linux/lsm.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include "../kselftest_harness.h" + +TEST(ctx_null_lsm_set_self_attr) +{ + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, NULL, + sizeof(struct lsm_ctx), 0)); +} + +TEST(size_too_small_lsm_set_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + struct lsm_ctx *ctx = calloc(page_size, 1); + __kernel_size_t size = page_size; + + ASSERT_NE(NULL, ctx); + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, + &size, 0)); + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, ctx, 1, + 0)); + + free(ctx); +} + +TEST(flags_zero_lsm_set_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *ctx = calloc(page_size, 1); + __kernel_size_t size = page_size; + + ASSERT_NE(NULL, ctx); + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, ctx, + &size, 0)); + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, LSM_ATTR_CURRENT, ctx, + size, 1)); + + free(ctx); +} + +TEST(flags_overset_lsm_set_self_attr) +{ + const long page_size = sysconf(_SC_PAGESIZE); + char *ctx = calloc(page_size, 1); + __kernel_size_t size = page_size; + struct lsm_ctx *tctx = (struct lsm_ctx *)ctx; + + ASSERT_NE(NULL, ctx); + ASSERT_GE(1, syscall(__NR_lsm_get_self_attr, LSM_ATTR_CURRENT, tctx, + &size, 0)); + ASSERT_EQ(-1, syscall(__NR_lsm_set_self_attr, + LSM_ATTR_CURRENT | LSM_ATTR_PREV, tctx, size, 0)); + + free(ctx); +} + +TEST_HARNESS_MAIN
Add selftests for the three system calls supporting the LSM infrastructure. Signed-off-by: Casey Schaufler <casey@schaufler-ca.com> --- tools/testing/selftests/Makefile | 1 + tools/testing/selftests/lsm/Makefile | 12 + tools/testing/selftests/lsm/config | 2 + .../selftests/lsm/lsm_get_self_attr_test.c | 267 ++++++++++++++++++ .../selftests/lsm/lsm_list_modules_test.c | 149 ++++++++++ .../selftests/lsm/lsm_set_self_attr_test.c | 70 +++++ 6 files changed, 501 insertions(+) create mode 100644 tools/testing/selftests/lsm/Makefile create mode 100644 tools/testing/selftests/lsm/config create mode 100644 tools/testing/selftests/lsm/lsm_get_self_attr_test.c create mode 100644 tools/testing/selftests/lsm/lsm_list_modules_test.c create mode 100644 tools/testing/selftests/lsm/lsm_set_self_attr_test.c