linux-kselftest-next-5.14-rc1
This Kselftest update for Linux 5.14-rc1 consists of fixes to existing tests and framework: -- migrate sgx test to kselftest harness -- add new test cases to sgx test -- ftrace test fix event-no-pid on 1-core machine -- splice test adjust for handler fallback removal -----BEGIN PGP SIGNATURE----- iQIzBAABCgAdFiEEPZKym/RZuOCGeA/kCwJExA0NQxwFAmDfQGUACgkQCwJExA0N Qxw6hw/+OEBEs+eHlDbbxHb9fBEg8kWls0AJKLAD2DEJOt1eARzyVa4J1MUpS6yK jJi/k0wKvqhMbdQgEEL3oSVvr9JgmOell0OkLzK9tx4HgEou89GnuO+wVRAeG87o QGDVWOa76GZwC47rvDDt9i9io075O1fol9HPgPZIdyVFcFgu45PVmRoSK4vaKUpm m5VtEznCxcL60vD+u2XhbBO2QMUi4OoBrNdJpnkBx/U6iCv5ZQbpN3OoDgdhltXC raQChLmy9bi2uYXskklcY1xGftyUiiWwfaiz7w6a65C2DedsUoD1lwhnaLlsJmSh KTOx9r5xF5bgRsdbWefIc7yRk9nVNczVSRs+x8aGlXT3p+e9jwaSXWXvCaZowYOV M+R0nCgmpOoGl5jhgeeu+P+JyC7aRRtMhVTGOiuUzyAPZbaIur1JVjoHpRHCVZle XjkCbq+VZ7Qb6pZ5sM+ve20GIw+J8/pDc4qtpttqb+hLtwe5rJj+Ydw2GQ/yZ30c uFwfdvGQMVMHjvPaL8IQb6WE3tiBhvJiUYQaRdR83HaWFstI14fFHgm7Zed9I19b TAgoDZ4P08cROtTbopbjRX1B3cnx/sUrFjwW8cTstIkedzo3rHbdf4UvV/h96O+S BjrZfsbEQBaCLW8KNu9wO/id+sPXeYwuW4HCkE0R0H1ZJI4Fgio= =6gOE -----END PGP SIGNATURE----- Merge tag 'linux-kselftest-next-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest Pull Kselftest update from Shuah Khan: "Fixes to existing tests and framework: - migrate sgx test to kselftest harness - add new test cases to sgx test - ftrace test fix event-no-pid on 1-core machine - splice test adjust for handler fallback removal" * tag 'linux-kselftest-next-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/shuah/linux-kselftest: selftests/sgx: remove checks for file execute permissions selftests/ftrace: fix event-no-pid on 1-core machine selftests/sgx: Refine the test enclave to have storage selftests/sgx: Add EXPECT_EEXIT() macro selftests/sgx: Dump enclave memory map selftests/sgx: Migrate to kselftest harness selftests/sgx: Rename 'eenter' and 'sgx_call_vdso' selftests: timers: rtcpie: skip test if default RTC device does not exist selftests: lib.mk: Also install "config" and "settings" selftests: splice: Adjust for handler fallback removal selftests/tls: Add {} to avoid static checker warning selftests/resctrl: Fix incorrect parsing of option "-t"
This commit is contained in:
commit
35e43538af
14 changed files with 309 additions and 139 deletions
|
@ -57,6 +57,10 @@ enable_events() {
|
||||||
echo 1 > tracing_on
|
echo 1 > tracing_on
|
||||||
}
|
}
|
||||||
|
|
||||||
|
other_task() {
|
||||||
|
sleep .001 || usleep 1 || sleep 1
|
||||||
|
}
|
||||||
|
|
||||||
echo 0 > options/event-fork
|
echo 0 > options/event-fork
|
||||||
|
|
||||||
do_reset
|
do_reset
|
||||||
|
@ -94,6 +98,9 @@ child=$!
|
||||||
echo "child = $child"
|
echo "child = $child"
|
||||||
wait $child
|
wait $child
|
||||||
|
|
||||||
|
# Be sure some other events will happen for small systems (e.g. 1 core)
|
||||||
|
other_task
|
||||||
|
|
||||||
echo 0 > tracing_on
|
echo 0 > tracing_on
|
||||||
|
|
||||||
cnt=`count_pid $mypid`
|
cnt=`count_pid $mypid`
|
||||||
|
|
|
@ -100,6 +100,7 @@ define INSTALL_RULE
|
||||||
$(eval INSTALL_LIST = $(TEST_CUSTOM_PROGS)) $(INSTALL_SINGLE_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_PROGS_EXTENDED)) $(INSTALL_SINGLE_RULE)
|
||||||
$(eval INSTALL_LIST = $(TEST_GEN_FILES)) $(INSTALL_SINGLE_RULE)
|
$(eval INSTALL_LIST = $(TEST_GEN_FILES)) $(INSTALL_SINGLE_RULE)
|
||||||
|
$(eval INSTALL_LIST = $(wildcard config settings)) $(INSTALL_SINGLE_RULE)
|
||||||
endef
|
endef
|
||||||
|
|
||||||
install: all
|
install: all
|
||||||
|
|
|
@ -444,8 +444,9 @@ TEST_F(tls, sendmsg_large)
|
||||||
EXPECT_EQ(sendmsg(self->cfd, &msg, 0), send_len);
|
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);
|
EXPECT_NE(recv(self->fd, mem, send_len, 0), -1);
|
||||||
|
}
|
||||||
|
|
||||||
free(mem);
|
free(mem);
|
||||||
}
|
}
|
||||||
|
|
|
@ -173,7 +173,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
token = strtok(NULL, ":\t");
|
token = strtok(NULL, ",");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 'p':
|
case 'p':
|
||||||
|
|
|
@ -5,8 +5,8 @@
|
||||||
|
|
||||||
.text
|
.text
|
||||||
|
|
||||||
.global sgx_call_vdso
|
.global sgx_enter_enclave
|
||||||
sgx_call_vdso:
|
sgx_enter_enclave:
|
||||||
.cfi_startproc
|
.cfi_startproc
|
||||||
push %r15
|
push %r15
|
||||||
.cfi_adjust_cfa_offset 8
|
.cfi_adjust_cfa_offset 8
|
||||||
|
@ -27,7 +27,7 @@ sgx_call_vdso:
|
||||||
.cfi_adjust_cfa_offset 8
|
.cfi_adjust_cfa_offset 8
|
||||||
push 0x38(%rsp)
|
push 0x38(%rsp)
|
||||||
.cfi_adjust_cfa_offset 8
|
.cfi_adjust_cfa_offset 8
|
||||||
call *eenter(%rip)
|
call *vdso_sgx_enter_enclave(%rip)
|
||||||
add $0x10, %rsp
|
add $0x10, %rsp
|
||||||
.cfi_adjust_cfa_offset -0x10
|
.cfi_adjust_cfa_offset -0x10
|
||||||
pop %rbx
|
pop %rbx
|
||||||
|
|
|
@ -18,4 +18,14 @@
|
||||||
#include "../../../../arch/x86/include/asm/enclu.h"
|
#include "../../../../arch/x86/include/asm/enclu.h"
|
||||||
#include "../../../../arch/x86/include/uapi/asm/sgx.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 */
|
#endif /* DEFINES_H */
|
||||||
|
|
|
@ -150,16 +150,6 @@ bool encl_load(const char *path, struct encl *encl)
|
||||||
goto err;
|
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);
|
ptr = mmap(NULL, PAGE_SIZE, PROT_READ, MAP_SHARED, fd, 0);
|
||||||
if (ptr == (void *)-1) {
|
if (ptr == (void *)-1) {
|
||||||
perror("mmap for read");
|
perror("mmap for read");
|
||||||
|
@ -169,13 +159,13 @@ bool encl_load(const char *path, struct encl *encl)
|
||||||
|
|
||||||
#define ERR_MSG \
|
#define ERR_MSG \
|
||||||
"mmap() succeeded for PROT_READ, but failed for PROT_EXEC.\n" \
|
"mmap() succeeded for PROT_READ, but failed for PROT_EXEC.\n" \
|
||||||
" Check that current user has execute permissions on %s and \n" \
|
" Check that /dev does not have noexec set:\n" \
|
||||||
" that /dev does not have noexec set: mount | grep \"/dev .*noexec\"\n" \
|
" \tmount | grep \"/dev .*noexec\"\n" \
|
||||||
" If so, remount it executable: mount -o remount,exec /dev\n\n"
|
" If so, remount it executable: mount -o remount,exec /dev\n\n"
|
||||||
|
|
||||||
ptr = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_SHARED, fd, 0);
|
ptr = mmap(NULL, PAGE_SIZE, PROT_EXEC, MAP_SHARED, fd, 0);
|
||||||
if (ptr == (void *)-1) {
|
if (ptr == (void *)-1) {
|
||||||
fprintf(stderr, ERR_MSG, device_path);
|
fprintf(stderr, ERR_MSG);
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
munmap(ptr, PAGE_SIZE);
|
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->offset = (phdr->p_offset & PAGE_MASK) - src_offset;
|
||||||
seg->size = (phdr->p_filesz + PAGE_SIZE - 1) & PAGE_MASK;
|
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++;
|
j++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,11 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/auxv.h>
|
#include <sys/auxv.h>
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
#include "../kselftest_harness.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "../kselftest.h"
|
|
||||||
|
|
||||||
static const uint64_t MAGIC = 0x1122334455667788ULL;
|
static const uint64_t MAGIC = 0x1122334455667788ULL;
|
||||||
vdso_sgx_enter_enclave_t eenter;
|
vdso_sgx_enter_enclave_t vdso_sgx_enter_enclave;
|
||||||
|
|
||||||
struct vdso_symtab {
|
struct vdso_symtab {
|
||||||
Elf64_Sym *elf_symtab;
|
Elf64_Sym *elf_symtab;
|
||||||
|
@ -107,84 +107,50 @@ static Elf64_Sym *vdso_symtab_get(struct vdso_symtab *symtab, const char *name)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool report_results(struct sgx_enclave_run *run, int ret, uint64_t result,
|
FIXTURE(enclave) {
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
|
||||||
{
|
|
||||||
struct sgx_enclave_run run;
|
|
||||||
struct vdso_symtab symtab;
|
|
||||||
Elf64_Sym *eenter_sym;
|
|
||||||
uint64_t result = 0;
|
|
||||||
struct encl encl;
|
struct encl encl;
|
||||||
|
struct sgx_enclave_run run;
|
||||||
|
};
|
||||||
|
|
||||||
|
FIXTURE_SETUP(enclave)
|
||||||
|
{
|
||||||
|
Elf64_Sym *sgx_enter_enclave_sym = NULL;
|
||||||
|
struct vdso_symtab symtab;
|
||||||
|
struct encl_segment *seg;
|
||||||
|
char maps_line[256];
|
||||||
|
FILE *maps_file;
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
void *addr;
|
void *addr;
|
||||||
int ret;
|
|
||||||
|
|
||||||
memset(&run, 0, sizeof(run));
|
if (!encl_load("test_encl.elf", &self->encl)) {
|
||||||
|
encl_delete(&self->encl);
|
||||||
if (!encl_load("test_encl.elf", &encl)) {
|
|
||||||
encl_delete(&encl);
|
|
||||||
ksft_exit_skip("cannot load enclaves\n");
|
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;
|
goto err;
|
||||||
|
|
||||||
if (!encl_build(&encl))
|
if (!encl_build(&self->encl))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* An enclave consumer only must do this.
|
* An enclave consumer only must do this.
|
||||||
*/
|
*/
|
||||||
for (i = 0; i < encl.nr_segments; i++) {
|
for (i = 0; i < self->encl.nr_segments; i++) {
|
||||||
struct encl_segment *seg = &encl.segment_tbl[i];
|
struct encl_segment *seg = &self->encl.segment_tbl[i];
|
||||||
|
|
||||||
addr = mmap((void *)encl.encl_base + seg->offset, seg->size,
|
addr = mmap((void *)self->encl.encl_base + seg->offset, seg->size,
|
||||||
seg->prot, MAP_SHARED | MAP_FIXED, encl.fd, 0);
|
seg->prot, MAP_SHARED | MAP_FIXED, self->encl.fd, 0);
|
||||||
if (addr == MAP_FAILED) {
|
EXPECT_NE(addr, MAP_FAILED);
|
||||||
perror("mmap() segment failed");
|
if (addr == MAP_FAILED)
|
||||||
exit(KSFT_FAIL);
|
goto err;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
memset(&run, 0, sizeof(run));
|
|
||||||
run.tcs = encl.encl_base;
|
|
||||||
|
|
||||||
/* Get vDSO base address */
|
/* Get vDSO base address */
|
||||||
addr = (void *)getauxval(AT_SYSINFO_EHDR);
|
addr = (void *)getauxval(AT_SYSINFO_EHDR);
|
||||||
|
@ -194,37 +160,134 @@ int main(int argc, char *argv[])
|
||||||
if (!vdso_get_symtab(addr, &symtab))
|
if (!vdso_get_symtab(addr, &symtab))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
eenter_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
|
sgx_enter_enclave_sym = vdso_symtab_get(&symtab, "__vdso_sgx_enter_enclave");
|
||||||
if (!eenter_sym)
|
if (!sgx_enter_enclave_sym)
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
eenter = addr + eenter_sym->st_value;
|
vdso_sgx_enter_enclave = addr + sgx_enter_enclave_sym->st_value;
|
||||||
|
|
||||||
ret = sgx_call_vdso((void *)&MAGIC, &result, 0, EENTER, NULL, NULL, &run);
|
memset(&self->run, 0, sizeof(self->run));
|
||||||
if (!report_results(&run, ret, result, "sgx_call_vdso"))
|
self->run.tcs = self->encl.encl_base;
|
||||||
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';
|
||||||
|
|
||||||
/* Invoke the vDSO directly. */
|
if (strstr(maps_line, "/dev/sgx_enclave"))
|
||||||
result = 0;
|
TH_LOG("%s", maps_line);
|
||||||
ret = eenter((unsigned long)&MAGIC, (unsigned long)&result, 0, EENTER,
|
}
|
||||||
0, 0, &run);
|
|
||||||
if (!report_results(&run, ret, result, "eenter"))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
/* And with an exit handler. */
|
fclose(maps_file);
|
||||||
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;
|
|
||||||
|
|
||||||
printf("SUCCESS\n");
|
|
||||||
encl_delete(&encl);
|
|
||||||
exit(KSFT_PASS);
|
|
||||||
|
|
||||||
err:
|
err:
|
||||||
encl_delete(&encl);
|
if (!sgx_enter_enclave_sym)
|
||||||
exit(KSFT_FAIL);
|
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_measure(struct encl *encl);
|
||||||
bool encl_build(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,
|
int sgx_enter_enclave(void *rdi, void *rsi, long rdx, u32 function, void *r8, void *r9,
|
||||||
struct sgx_enclave_run *run);
|
struct sgx_enclave_run *run);
|
||||||
|
|
||||||
#endif /* MAIN_H */
|
#endif /* MAIN_H */
|
||||||
|
|
|
@ -4,6 +4,8 @@
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include "defines.h"
|
#include "defines.h"
|
||||||
|
|
||||||
|
static uint8_t encl_buffer[8192] = { 1 };
|
||||||
|
|
||||||
static void *memcpy(void *dest, const void *src, size_t n)
|
static void *memcpy(void *dest, const void *src, size_t n)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
|
@ -16,5 +18,18 @@ static void *memcpy(void *dest, const void *src, size_t n)
|
||||||
|
|
||||||
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 : {
|
||||||
*(.text*)
|
*(.text*)
|
||||||
*(.rodata*)
|
*(.rodata*)
|
||||||
|
FILL(0xDEADBEEF);
|
||||||
|
. = ALIGN(4096);
|
||||||
} : text
|
} : text
|
||||||
|
|
||||||
. = ALIGN(4096);
|
|
||||||
.data : {
|
.data : {
|
||||||
*(.data*)
|
*(.data*)
|
||||||
} : data
|
} : data
|
||||||
|
|
|
@ -1,21 +1,87 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
# SPDX-License-Identifier: GPL-2.0
|
# 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
|
set -e
|
||||||
|
|
||||||
|
DIR=$(dirname "$0")
|
||||||
|
|
||||||
ret=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()
|
do_splice()
|
||||||
{
|
{
|
||||||
filename="$1"
|
filename="$1"
|
||||||
bytes="$2"
|
bytes="$2"
|
||||||
expected="$3"
|
expected="$3"
|
||||||
|
report="$4"
|
||||||
|
|
||||||
out=$(./splice_read "$filename" "$bytes" | cat)
|
out=$("$DIR"/splice_read "$filename" "$bytes" | cat)
|
||||||
if [ "$out" = "$expected" ] ; then
|
if [ "$out" = "$expected" ] ; then
|
||||||
echo "ok: $filename $bytes"
|
echo " matched $report" >&2
|
||||||
|
return 0
|
||||||
else
|
else
|
||||||
echo "FAIL: $filename $bytes"
|
echo " no match: '$out' vs $report" >&2
|
||||||
ret=1
|
return 1
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,34 +89,45 @@ test_splice()
|
||||||
{
|
{
|
||||||
filename="$1"
|
filename="$1"
|
||||||
|
|
||||||
|
echo " checking $filename ..." >&2
|
||||||
|
|
||||||
full=$(cat "$filename")
|
full=$(cat "$filename")
|
||||||
|
rc=$?
|
||||||
|
if [ $rc -ne 0 ] ; then
|
||||||
|
return 2
|
||||||
|
fi
|
||||||
|
|
||||||
two=$(echo "$full" | grep -m1 . | cut -c-2)
|
two=$(echo "$full" | grep -m1 . | cut -c-2)
|
||||||
|
|
||||||
# Make sure full splice has the same contents as a standard read.
|
# 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.
|
# 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()
|
### /proc/$pid/ has no splice interface; these should all fail.
|
||||||
test_splice /proc/$$/limits
|
expect_failure "proc_single_open(), seq_read() splice" test_splice /proc/$$/limits
|
||||||
# special open, seq_read()
|
expect_failure "special open(), seq_read() splice" test_splice /proc/$$/comm
|
||||||
test_splice /proc/$$/comm
|
|
||||||
|
|
||||||
# proc_handler, proc_dointvec_minmax
|
### /proc/sys/ has a splice interface; these should all succeed.
|
||||||
test_splice /proc/sys/fs/nr_open
|
expect_success "proc_handler: proc_dointvec_minmax() splice" test_splice /proc/sys/fs/nr_open
|
||||||
# proc_handler, proc_dostring
|
expect_success "proc_handler: proc_dostring() splice" test_splice /proc/sys/kernel/modprobe
|
||||||
test_splice /proc/sys/kernel/modprobe
|
expect_success "proc_handler: special read splice" test_splice /proc/sys/kernel/version
|
||||||
# proc_handler, special read
|
|
||||||
test_splice /proc/sys/kernel/version
|
|
||||||
|
|
||||||
|
### /sys/ has no splice interface; these should all fail.
|
||||||
if ! [ -d /sys/module/test_module/sections ] ; then
|
if ! [ -d /sys/module/test_module/sections ] ; then
|
||||||
modprobe test_module
|
expect_success "test_module kernel module load" modprobe test_module
|
||||||
fi
|
fi
|
||||||
# kernfs, attr
|
expect_failure "kernfs attr splice" test_splice /sys/module/test_module/coresize
|
||||||
test_splice /sys/module/test_module/coresize
|
expect_failure "kernfs binattr splice" test_splice /sys/module/test_module/sections/.init.text
|
||||||
# kernfs, binattr
|
|
||||||
test_splice /sys/module/test_module/sections/.init.text
|
|
||||||
|
|
||||||
exit $ret
|
exit $ret
|
||||||
|
|
|
@ -18,6 +18,8 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "../kselftest.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This expects the new RTC class driver framework, working with
|
* This expects the new RTC class driver framework, working with
|
||||||
* clocks that will often not be clones of what the PC-AT had.
|
* 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) {
|
switch (argc) {
|
||||||
case 2:
|
case 2:
|
||||||
rtc = argv[1];
|
rtc = argv[1];
|
||||||
/* FALLTHROUGH */
|
break;
|
||||||
case 1:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
fprintf(stderr, "usage: rtctest [rtcdev] [d]\n");
|
fprintf(stderr, "usage: rtctest [rtcdev] [d]\n");
|
||||||
|
|
Loading…
Add table
Reference in a new issue