@@ -57,6 +57,10 @@ enable_events() {
echo 1 > tracing_on
}
+other_task() {
+ sleep .001 || usleep 1 || sleep 1
+}
+
echo 0 > options/event-fork
do_reset
@@ -94,6 +98,9 @@ child=$!
echo "child = $child"
wait $child
+# Be sure some other events will happen for small systems (e.g. 1 core)
+other_task
+
echo 0 > tracing_on
cnt=`count_pid $mypid`
@@ -100,6 +100,7 @@ define INSTALL_RULE
$(eval INSTALL_LIST = $(TEST_CUSTOM_PROGS)) $(INSTALL_SINGLE_RULE)
$(eval INSTALL_LIST = $(TEST_GEN_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE)
$(eval INSTALL_LIST = $(TEST_GEN_FILES)) $(INSTALL_SINGLE_RULE)
+ $(eval INSTALL_LIST = $(wildcard config settings)) $(INSTALL_SINGLE_RULE)
endef
install: all
@@ -418,8 +418,9 @@ TEST_F(tls, sendmsg_large)
EXPECT_EQ(sendmsg(self->cfd, &msg, 0), send_len);
}
- while (recvs++ < sends)
+ while (recvs++ < sends) {
EXPECT_NE(recv(self->fd, mem, send_len, 0), -1);
+ }
free(mem);
}
@@ -47,7 +47,7 @@ Parameter '-h' shows usage information.
usage: resctrl_tests [-h] [-b "benchmark_cmd [options]"] [-t test list] [-n no_of_bits]
-b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CMT default benchmark is builtin fill_buf
- -t test list: run tests specified in the test list, e.g. -t mbm, mba, cmt, cat
+ -t test list: run tests specified in the test list, e.g. -t mbm,mba,cmt,cat
-n no_of_bits: run cache tests using specified no of bits in cache bit mask
-p cpu_no: specify CPU number to run the test. 1 is default
-h: help
@@ -40,7 +40,7 @@ static void cmd_help(void)
printf("\t-b benchmark_cmd [options]: run specified benchmark for MBM, MBA and CMT\n");
printf("\t default benchmark is builtin fill_buf\n");
printf("\t-t test list: run tests specified in the test list, ");
- printf("e.g. -t mbm, mba, cmt, cat\n");
+ printf("e.g. -t mbm,mba,cmt,cat\n");
printf("\t-n no_of_bits: run cache tests using specified no of bits in cache bit mask\n");
printf("\t-p cpu_no: specify CPU number to run the test. 1 is default\n");
printf("\t-h: help\n");
@@ -173,7 +173,7 @@ int main(int argc, char **argv)
return -1;
}
- token = strtok(NULL, ":\t");
+ token = strtok(NULL, ",");
}
break;
case 'p':
@@ -5,8 +5,8 @@
.text
- .global sgx_call_vdso
-sgx_call_vdso:
+ .global sgx_enter_enclave
+sgx_enter_enclave:
.cfi_startproc
push %r15
.cfi_adjust_cfa_offset 8
@@ -27,7 +27,7 @@ sgx_call_vdso:
.cfi_adjust_cfa_offset 8
push 0x38(%rsp)
.cfi_adjust_cfa_offset 8
- call *eenter(%rip)
+ call *vdso_sgx_enter_enclave(%rip)
add $0x10, %rsp
.cfi_adjust_cfa_offset -0x10
pop %rbx
@@ -18,4 +18,14 @@
#include "../../../../arch/x86/include/asm/enclu.h"
#include "../../../../arch/x86/include/uapi/asm/sgx.h"
+enum encl_op_type {
+ ENCL_OP_PUT,
+ ENCL_OP_GET,
+};
+
+struct encl_op {
+ uint64_t type;
+ uint64_t buffer;
+};
+
#endif /* DEFINES_H */
@@ -150,16 +150,6 @@ bool encl_load(const char *path, struct encl *encl)
goto err;
}
- /*
- * This just checks if the /dev file has these permission
- * bits set. It does not check that the current user is
- * the owner or in the owning group.
- */
- if (!(sb.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH))) {
- fprintf(stderr, "no execute permissions on device file %s\n", device_path);
- goto err;
- }
-
ptr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
if (ptr == (void *)-1) {
perror("mmap for read");
@@ -169,13 +159,13 @@ bool encl_load(const char *path, struct encl *encl)
#define ERR_MSG \
"mmap() succeeded for PROT_READ, but failed for PROT_EXEC.\n" \
-" Check that current user has execute permissions on %s and \n" \
-" that /dev does not have noexec set: mount | grep \"/dev .*noexec\"\n" \
+" Check that /dev does not have noexec set:\n" \
+" \tmount | grep \"/dev .*noexec\"\n" \
" If so, remount it executable: mount -o remount,exec /dev\n\n"
ptr = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_SHARED, fd, 0);
if (ptr == (void *)-1) {
- fprintf(stderr, ERR_MSG, device_path);
+ fprintf(stderr, ERR_MSG);
goto err;
}
munmap(ptr, PAGE_SIZE);
@@ -239,9 +229,6 @@ bool encl_load(const char *path, struct encl *encl)
seg->offset = (phdr->p_offset & PAGE_MASK) - src_offset;
seg->size = (phdr->p_filesz + PAGE_SIZE - 1) & PAGE_MASK;
- printf("0x%016lx 0x%016lx 0x%02x\n", seg->offset, seg->size,
- seg->prot);
-
j++;
}
@@ -17,11 +17,11 @@
#include <sys/types.h>
#include <sys/auxv.h>
#include "defines.h"
+#include "../kselftest_harness.h"
#include "main.h"
-#include "../kselftest.h"
static const uint64_t MAGIC = 0x1122334455667788ULL;
-vdso_sgx_enter_enclave_t eenter;
+vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave;
struct vdso_symtab {
Elf64_Sym *elf_symtab;
@@ -107,85 +107,51 @@ static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name)
return NULL;
}
-bool report_results(struct sgx_enclave_run *run, int ret, uint64_t result,
- const char *test)
-{
- bool valid = true;
-
- if (ret) {
- printf("FAIL: %s() returned: %d\n", test, ret);
- valid = false;
- }
-
- if (run->function != EEXIT) {
- printf("FAIL: %s() function, expected: %u, got: %u\n", test, EEXIT,
- run->function);
- valid = false;
- }
-
- if (result != MAGIC) {
- printf("FAIL: %s(), expected: 0x%lx, got: 0x%lx\n", test, MAGIC,
- result);
- valid = false;
- }
-
- if (run->user_data) {
- printf("FAIL: %s() user data, expected: 0x0, got: 0x%llx\n",
- test, run->user_data);
- valid = false;
- }
-
- return valid;
-}
-
-static int user_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9,
- struct sgx_enclave_run *run)
-{
- run->user_data = 0;
- return 0;
-}
+FIXTURE(enclave) {
+ struct encl encl;
+ struct sgx_enclave_run run;
+};
-int main(int argc, char *argv[])
+FIXTURE_SETUP(enclave)
{
- struct sgx_enclave_run run;
+ Elf64_Sym *sgx_enter_enclave_sym = NULL;
struct vdso_symtab symtab;
- Elf64_Sym *eenter_sym;
- uint64_t result = 0;
- struct encl encl;
+ struct encl_segment *seg;
+ char maps_line[256];
+ FILE *maps_file;
unsigned int i;
void *addr;
- int ret;
- memset(&run, 0, sizeof(run));
-
- if (!encl_load("test_encl.elf", &encl)) {
- encl_delete(&encl);
+ if (!encl_load("test_encl.elf", &self->encl)) {
+ encl_delete(&self->encl);
ksft_exit_skip("cannot load enclaves\n");
}
- if (!encl_measure(&encl))
+ for (i = 0; i < self->encl.nr_segments; i++) {
+ seg = &self->encl.segment_tbl[i];
+
+ TH_LOG("0x%016lx 0x%016lx 0x%02x", seg->offset, seg->size, seg->prot);
+ }
+
+ if (!encl_measure(&self->encl))
goto err;
- if (!encl_build(&encl))
+ if (!encl_build(&self->encl))
goto err;
/*
* An enclave consumer only must do this.
*/
- for (i = 0; i < encl.nr_segments; i++) {
- struct encl_segment *seg = &encl.segment_tbl[i];
-
- addr = mmap((void *)encl.encl_base + seg->offset, seg->size,
- seg->prot, MAP_SHARED | MAP_FIXED, encl.fd, 0);
- if (addr == MAP_FAILED) {
- perror("mmap() segment failed");
- exit(KSFT_FAIL);
- }
+ for (i = 0; i < self->encl.nr_segments; i++) {
+ struct encl_segment *seg = &self->encl.segment_tbl[i];
+
+ addr = mmap((void *)self->encl.encl_base + seg->offset, seg->size,
+ seg->prot, MAP_SHARED | MAP_FIXED, self->encl.fd, 0);
+ EXPECT_NE(addr, MAP_FAILED);
+ if (addr == MAP_FAILED)
+ goto err;
}
- memset(&run, 0, sizeof(run));
- run.tcs = encl.encl_base;
-
/* Get vDSO base address */
addr = (void *)getauxval(AT_SYSINFO_EHDR);
if (!addr)
@@ -194,37 +160,134 @@ int main(int argc, char *argv[])
if (!vdso_get_symtab(addr, &symtab))
goto err;
- eenter_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
- if (!eenter_sym)
+ sgx_enter_enclave_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
+ if (!sgx_enter_enclave_sym)
goto err;
- eenter = addr + eenter_sym->st_value;
-
- ret = sgx_call_vdso((void *)&MAGIC, &result, 0, EENTER, NULL, NULL, &run);
- if (!report_results(&run, ret, result, "sgx_call_vdso"))
- goto err;
+ vdso_sgx_enter_enclave = addr + sgx_enter_enclave_sym->st_value;
+ memset(&self->run, 0, sizeof(self->run));
+ self->run.tcs = self->encl.encl_base;
- /* Invoke the vDSO directly. */
- result = 0;
- ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER,
- 0, 0, &run);
- if (!report_results(&run, ret, result, "eenter"))
- goto err;
+ maps_file = fopen("/proc/self/maps", "r");
+ if (maps_file != NULL) {
+ while (fgets(maps_line, sizeof(maps_line), maps_file) != NULL) {
+ maps_line[strlen(maps_line) - 1] = '\0';
- /* And with an exit handler. */
- run.user_handler = (__u64)user_handler;
- run.user_data = 0xdeadbeef;
- ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER,
- 0, 0, &run);
- if (!report_results(&run, ret, result, "user_handler"))
- goto err;
+ if (strstr(maps_line, "/dev/sgx_enclave"))
+ TH_LOG("%s", maps_line);
+ }
- printf("SUCCESS\n");
- encl_delete(&encl);
- exit(KSFT_PASS);
+ fclose(maps_file);
+ }
err:
- encl_delete(&encl);
- exit(KSFT_FAIL);
+ if (!sgx_enter_enclave_sym)
+ encl_delete(&self->encl);
+
+ ASSERT_NE(sgx_enter_enclave_sym, NULL);
+}
+
+FIXTURE_TEARDOWN(enclave)
+{
+ encl_delete(&self->encl);
+}
+
+#define ENCL_CALL(op, run, clobbered) \
+ ({ \
+ int ret; \
+ if ((clobbered)) \
+ ret = vdso_sgx_enter_enclave((unsigned long)(op), 0, 0, \
+ EENTER, 0, 0, (run)); \
+ else \
+ ret = sgx_enter_enclave((void *)(op), NULL, 0, EENTER, NULL, NULL, \
+ (run)); \
+ ret; \
+ })
+
+#define EXPECT_EEXIT(run) \
+ do { \
+ EXPECT_EQ((run)->function, EEXIT); \
+ if ((run)->function != EEXIT) \
+ TH_LOG("0x%02x 0x%02x 0x%016llx", (run)->exception_vector, \
+ (run)->exception_error_code, (run)->exception_addr); \
+ } while (0)
+
+TEST_F(enclave, unclobbered_vdso)
+{
+ struct encl_op op;
+
+ op.type = ENCL_OP_PUT;
+ op.buffer = MAGIC;
+
+ EXPECT_EQ(ENCL_CALL(&op, &self->run, false), 0);
+
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.user_data, 0);
+
+ op.type = ENCL_OP_GET;
+ op.buffer = 0;
+
+ EXPECT_EQ(ENCL_CALL(&op, &self->run, false), 0);
+
+ EXPECT_EQ(op.buffer, MAGIC);
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.user_data, 0);
+}
+
+TEST_F(enclave, clobbered_vdso)
+{
+ struct encl_op op;
+
+ op.type = ENCL_OP_PUT;
+ op.buffer = MAGIC;
+
+ EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
+
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.user_data, 0);
+
+ op.type = ENCL_OP_GET;
+ op.buffer = 0;
+
+ EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
+
+ EXPECT_EQ(op.buffer, MAGIC);
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.user_data, 0);
}
+
+static int test_handler(long rdi, long rsi, long rdx, long ursp, long r8, long r9,
+ struct sgx_enclave_run *run)
+{
+ run->user_data = 0;
+
+ return 0;
+}
+
+TEST_F(enclave, clobbered_vdso_and_user_function)
+{
+ struct encl_op op;
+
+ self->run.user_handler = (__u64)test_handler;
+ self->run.user_data = 0xdeadbeef;
+
+ op.type = ENCL_OP_PUT;
+ op.buffer = MAGIC;
+
+ EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
+
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.user_data, 0);
+
+ op.type = ENCL_OP_GET;
+ op.buffer = 0;
+
+ EXPECT_EQ(ENCL_CALL(&op, &self->run, true), 0);
+
+ EXPECT_EQ(op.buffer, MAGIC);
+ EXPECT_EEXIT(&self->run);
+ EXPECT_EQ(self->run.user_data, 0);
+}
+
+TEST_HARNESS_MAIN
@@ -35,7 +35,7 @@ bool encl_load(const char *path, struct encl *encl);
bool encl_measure(struct encl *encl);
bool encl_build(struct encl *encl);
-int sgx_call_vdso(void *rdi, void *rsi, long rdx, u32 function, void *r8, void *r9,
- struct sgx_enclave_run *run);
+int sgx_enter_enclave(void *rdi, void *rsi, long rdx, u32 function, void *r8, void *r9,
+ struct sgx_enclave_run *run);
#endif /* MAIN_H */
@@ -4,6 +4,8 @@
#include <stddef.h>
#include "defines.h"
+static uint8_t encl_buffer[8192] = { 1 };
+
static void *memcpy(void *dest, const void *src, size_t n)
{
size_t i;
@@ -14,7 +16,20 @@ static void *memcpy(void *dest, const void *src, size_t n)
return dest;
}
-void encl_body(void *rdi, void *rsi)
+void encl_body(void *rdi, void *rsi)
{
- memcpy(rsi, rdi, 8);
+ struct encl_op *op = (struct encl_op *)rdi;
+
+ switch (op->type) {
+ case ENCL_OP_PUT:
+ memcpy(&encl_buffer[0], &op->buffer, 8);
+ break;
+
+ case ENCL_OP_GET:
+ memcpy(&op->buffer, &encl_buffer[0], 8);
+ break;
+
+ default:
+ break;
+ }
}
@@ -18,9 +18,10 @@ SECTIONS
.text : {
*(.text*)
*(.rodata*)
+ FILL(0xDEADBEEF);
+ . = ALIGN(4096);
} : text
- . = ALIGN(4096);
.data : {
*(.data*)
} : data
@@ -1,21 +1,87 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
+#
+# Test for mishandling of splice() on pseudofilesystems, which should catch
+# bugs like 11990a5bd7e5 ("module: Correctly truncate sysfs sections output")
+#
+# Since splice fallback was removed as part of the set_fs() rework, many of these
+# tests expect to fail now. See https://lore.kernel.org/lkml/202009181443.C2179FB@keescook/
set -e
+DIR=$(dirname "$0")
+
ret=0
+expect_success()
+{
+ title="$1"
+ shift
+
+ echo "" >&2
+ echo "$title ..." >&2
+
+ set +e
+ "$@"
+ rc=$?
+ set -e
+
+ case "$rc" in
+ 0)
+ echo "ok: $title succeeded" >&2
+ ;;
+ 1)
+ echo "FAIL: $title should work" >&2
+ ret=$(( ret + 1 ))
+ ;;
+ *)
+ echo "FAIL: something else went wrong" >&2
+ ret=$(( ret + 1 ))
+ ;;
+ esac
+}
+
+expect_failure()
+{
+ title="$1"
+ shift
+
+ echo "" >&2
+ echo "$title ..." >&2
+
+ set +e
+ "$@"
+ rc=$?
+ set -e
+
+ case "$rc" in
+ 0)
+ echo "FAIL: $title unexpectedly worked" >&2
+ ret=$(( ret + 1 ))
+ ;;
+ 1)
+ echo "ok: $title correctly failed" >&2
+ ;;
+ *)
+ echo "FAIL: something else went wrong" >&2
+ ret=$(( ret + 1 ))
+ ;;
+ esac
+}
+
do_splice()
{
filename="$1"
bytes="$2"
expected="$3"
+ report="$4"
- out=$(./splice_read "$filename" "$bytes" | cat)
+ out=$("$DIR"/splice_read "$filename" "$bytes" | cat)
if [ "$out" = "$expected" ] ; then
- echo "ok: $filename $bytes"
+ echo " matched $report" >&2
+ return 0
else
- echo "FAIL: $filename $bytes"
- ret=1
+ echo " no match: '$out' vs $report" >&2
+ return 1
fi
}
@@ -23,34 +89,45 @@ test_splice()
{
filename="$1"
+ echo " checking $filename ..." >&2
+
full=$(cat "$filename")
+ rc=$?
+ if [ $rc -ne 0 ] ; then
+ return 2
+ fi
+
two=$(echo "$full" | grep -m1 . | cut -c-2)
# Make sure full splice has the same contents as a standard read.
- do_splice "$filename" 4096 "$full"
+ echo " splicing 4096 bytes ..." >&2
+ if ! do_splice "$filename" 4096 "$full" "full read" ; then
+ return 1
+ fi
# Make sure a partial splice see the first two characters.
- do_splice "$filename" 2 "$two"
+ echo " splicing 2 bytes ..." >&2
+ if ! do_splice "$filename" 2 "$two" "'$two'" ; then
+ return 1
+ fi
+
+ return 0
}
-# proc_single_open(), seq_read()
-test_splice /proc/$$/limits
-# special open, seq_read()
-test_splice /proc/$$/comm
+### /proc/$pid/ has no splice interface; these should all fail.
+expect_failure "proc_single_open(), seq_read() splice" test_splice /proc/$$/limits
+expect_failure "special open(), seq_read() splice" test_splice /proc/$$/comm
-# proc_handler, proc_dointvec_minmax
-test_splice /proc/sys/fs/nr_open
-# proc_handler, proc_dostring
-test_splice /proc/sys/kernel/modprobe
-# proc_handler, special read
-test_splice /proc/sys/kernel/version
+### /proc/sys/ has a splice interface; these should all succeed.
+expect_success "proc_handler: proc_dointvec_minmax() splice" test_splice /proc/sys/fs/nr_open
+expect_success "proc_handler: proc_dostring() splice" test_splice /proc/sys/kernel/modprobe
+expect_success "proc_handler: special read splice" test_splice /proc/sys/kernel/version
+### /sys/ has no splice interface; these should all fail.
if ! [ -d /sys/module/test_module/sections ] ; then
- modprobe test_module
+ expect_success "test_module kernel module load" modprobe test_module
fi
-# kernfs, attr
-test_splice /sys/module/test_module/coresize
-# kernfs, binattr
-test_splice /sys/module/test_module/sections/.init.text
+expect_failure "kernfs attr splice" test_splice /sys/module/test_module/coresize
+expect_failure "kernfs binattr splice" test_splice /sys/module/test_module/sections/.init.text
exit $ret
@@ -18,6 +18,8 @@
#include <stdlib.h>
#include <errno.h>
+#include "../kselftest.h"
+
/*
* This expects the new RTC class driver framework, working with
* clocks that will often not be clones of what the PC-AT had.
@@ -35,8 +37,14 @@ int main(int argc, char **argv)
switch (argc) {
case 2:
rtc = argv[1];
- /* FALLTHROUGH */
+ break;
case 1:
+ fd = open(default_rtc, O_RDONLY);
+ if (fd == -1) {
+ printf("Default RTC %s does not exist. Test Skipped!\n", default_rtc);
+ exit(KSFT_SKIP);
+ }
+ close(fd);
break;
default:
fprintf(stderr, "usage: rtctest [rtcdev] [d]\n");