| // 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> |
| */ |
| |
| #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" |
| #include "common.h" |
| |
| 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); |
| struct lsm_ctx *ctx = calloc(page_size, 1); |
| |
| ASSERT_NE(NULL, ctx); |
| errno = 0; |
| ASSERT_EQ(-1, 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); |
| size_t size = page_size; |
| int rc; |
| |
| rc = lsm_get_self_attr(LSM_ATTR_CURRENT, NULL, &size, 0); |
| |
| if (attr_lsm_count()) { |
| ASSERT_NE(-1, rc); |
| ASSERT_NE(1, size); |
| } else { |
| ASSERT_EQ(-1, rc); |
| } |
| } |
| |
| TEST(size_too_small_lsm_get_self_attr) |
| { |
| const long page_size = sysconf(_SC_PAGESIZE); |
| struct lsm_ctx *ctx = calloc(page_size, 1); |
| size_t size = 1; |
| |
| ASSERT_NE(NULL, ctx); |
| errno = 0; |
| ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, 0)); |
| if (attr_lsm_count()) { |
| ASSERT_EQ(E2BIG, errno); |
| } else { |
| ASSERT_EQ(EOPNOTSUPP, errno); |
| } |
| ASSERT_NE(1, size); |
| |
| free(ctx); |
| } |
| |
| TEST(flags_zero_lsm_get_self_attr) |
| { |
| const long page_size = sysconf(_SC_PAGESIZE); |
| struct lsm_ctx *ctx = calloc(page_size, 1); |
| __u64 *syscall_lsms = calloc(page_size, 1); |
| size_t size; |
| int lsmcount; |
| int i; |
| |
| ASSERT_NE(NULL, ctx); |
| errno = 0; |
| size = page_size; |
| ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, |
| LSM_FLAG_SINGLE)); |
| ASSERT_EQ(EINVAL, errno); |
| ASSERT_EQ(page_size, size); |
| |
| lsmcount = syscall(__NR_lsm_list_modules, syscall_lsms, &size, 0); |
| ASSERT_LE(1, lsmcount); |
| ASSERT_NE(NULL, syscall_lsms); |
| |
| for (i = 0; i < lsmcount; i++) { |
| errno = 0; |
| size = page_size; |
| ctx->id = syscall_lsms[i]; |
| |
| if (syscall_lsms[i] == LSM_ID_SELINUX || |
| syscall_lsms[i] == LSM_ID_SMACK || |
| syscall_lsms[i] == LSM_ID_APPARMOR) { |
| ASSERT_EQ(1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, |
| &size, LSM_FLAG_SINGLE)); |
| } else { |
| ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, |
| &size, |
| LSM_FLAG_SINGLE)); |
| } |
| } |
| |
| free(ctx); |
| } |
| |
| TEST(flags_overset_lsm_get_self_attr) |
| { |
| const long page_size = sysconf(_SC_PAGESIZE); |
| struct lsm_ctx *ctx = calloc(page_size, 1); |
| size_t size; |
| |
| ASSERT_NE(NULL, ctx); |
| |
| errno = 0; |
| size = page_size; |
| ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT | LSM_ATTR_PREV, ctx, |
| &size, 0)); |
| ASSERT_EQ(EOPNOTSUPP, errno); |
| |
| errno = 0; |
| size = page_size; |
| ASSERT_EQ(-1, lsm_get_self_attr(LSM_ATTR_CURRENT, ctx, &size, |
| LSM_FLAG_SINGLE | |
| (LSM_FLAG_SINGLE << 1))); |
| ASSERT_EQ(EINVAL, errno); |
| |
| free(ctx); |
| } |
| |
| TEST(basic_lsm_get_self_attr) |
| { |
| const long page_size = sysconf(_SC_PAGESIZE); |
| 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 = 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 = 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 = 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 = 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 = 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 = 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 |