From 33cba1ad486ca96e0c3fa4277257201d2e615cb0 Mon Sep 17 00:00:00 2001 From: "Shiratori, Takehiro" Date: Mon, 16 Mar 2020 14:09:35 +0900 Subject: [PATCH] test: ptrace: Record syscall return value before reporting Change-Id: I8e9de3bb9bfa0b07eebe472131cc62b53ef5cc8b Refs: #1287 --- test/issues/1287/arm64/1287.sh | 42 +++++ test/issues/1287/arm64/1287_arm64.c | 259 ++++++++++++++++++++++++++++ test/issues/1287/arm64/Makefile | 10 ++ test/issues/1287/arm64/README | 30 ++++ 4 files changed, 341 insertions(+) create mode 100755 test/issues/1287/arm64/1287.sh create mode 100644 test/issues/1287/arm64/1287_arm64.c create mode 100644 test/issues/1287/arm64/Makefile create mode 100644 test/issues/1287/arm64/README diff --git a/test/issues/1287/arm64/1287.sh b/test/issues/1287/arm64/1287.sh new file mode 100755 index 00000000..9ae74233 --- /dev/null +++ b/test/issues/1287/arm64/1287.sh @@ -0,0 +1,42 @@ +#!/bin/sh +# 1287.sh COPYRIGHT FUJITSU LIMITED 2020 + +. $HOME/.mck_test_config + +BOOTPARAM="-c 12-15 -m 512M@4 -O" +USELTP=1 +FAIL=0 + +. ../../../common.sh + +echo "issue-1287 test run." + +${MCEXEC} ./1287_arm64 +if [ $? -eq 0 ]; then + echo "TEST001:OK." +else + echo "TEST001:NG." + FAIL=1 +fi + +echo "LTP: ptrace run." + +ltp=("01" "02" "03" "05") + +pushd ${LTPBIN} > /dev/null +for num in ${ltp[@]} +do + ${MCEXEC} ./ptrace${num} + if [ $? -ne 0 ]; then + FAIL=1 + fi +done +popd > /dev/null + +if [ ${FAIL} -eq 0 ]; then + echo "issue-1287 test OK." +else + echo "issue-1287 test NG." +fi + +mcstop diff --git a/test/issues/1287/arm64/1287_arm64.c b/test/issues/1287/arm64/1287_arm64.c new file mode 100644 index 00000000..2ad85854 --- /dev/null +++ b/test/issues/1287/arm64/1287_arm64.c @@ -0,0 +1,259 @@ +/* 1287_arm64.c COPYRIGHT FUJITSU LIMITED 2019 */ +/* ptrace(PTRACE_SYSCALL) args and ret check testcase */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static unsigned long __inst_addr; + +#define SYSCALL_ARG0 0x11111111 +#define SYSCALL_ARG1 0x22222222 +#define SYSCALL_ARG2 0x33333333 +#define SYSCALL_ARG3 0x44444444 +#define SYSCALL_ARG4 0x55555555 +#define SYSCALL_ARG5 0x66666666 + +#define NOP_INST 0xd503201fUL + +static int rewrite_brk_inst(pid_t cpid, void *inst_addr) +{ + unsigned long addr = 0; + const unsigned long inst = ((NOP_INST << 32UL) | NOP_INST); + + /* read child brk address */ + addr = ptrace(PTRACE_PEEKDATA, cpid, inst_addr, NULL); + if ((addr == -1) && errno) { + perror("ptrace(PTRACE_PEEKDATA)"); + return -1; + } + + /* write nop instruction */ + if (ptrace(PTRACE_POKETEXT, cpid, addr, inst)) { + perror("ptrace(PTRACE_POKETEXT)"); + return -1; + } + return 0; +} + +static int get_check_regs(pid_t cpid, int regnum, long exp) +{ + int ret = -1; + struct iovec iov; + struct user_pt_regs gregs; + + if (regnum < 0 || 30 < regnum) { + printf("regnum=%d invalid. (0 <= regnum <= 30)\n", regnum); + goto out; + } + + /* read child regs (REGSET_GPR) */ + iov.iov_base = &gregs; + iov.iov_len = sizeof(gregs); + if (ptrace(PTRACE_GETREGSET, cpid, NT_PRSTATUS, &iov)) { + perror("ptrace(PTRACE_GETREGSET, NT_PRSTATUS)"); + goto out; + } + + /* check */ + if (gregs.regs[regnum] != exp) { + printf("reg[%d] check NG.\n", regnum); + printf("expection:0x%lx readsysno:0x%llx\n", + exp, gregs.regs[regnum]); + goto out; + } + + /* success */ + ret = 0; +out: + return ret; +} + +static int child_func(void) +{ + int ret = -1; + + /* send PTRACE_TRACEME */ + if (ptrace(PTRACE_TRACEME, 0, NULL, NULL)) { + perror("ptrace(PTRACE_TRACEME)"); + goto out; + } + + /* stop mine, brk instruction */ + /* rewrite nop from parent process */ + asm volatile( + "adr x10, 1f\n" + "str x10, [%0]\n" + "nop\n" + "nop\n" + "1:\n" + "brk #0\n" + "nop\n" + : /* nothing */ + : "r"(&__inst_addr) + : "x10" + ); + + /* send magicno syscall */ + syscall(__NR_getpid, SYSCALL_ARG0, SYSCALL_ARG1, SYSCALL_ARG2, + SYSCALL_ARG3, SYSCALL_ARG4, SYSCALL_ARG5); + + /* success */ + ret = 0; +out: + return ret; +} + +static int parent_func(pid_t cpid) +{ + pid_t pid = 0; + int status = 0; + int ret = -1; + int i = 0; + const long syscall_args[] = { + SYSCALL_ARG0, SYSCALL_ARG1, SYSCALL_ARG2, + SYSCALL_ARG3, SYSCALL_ARG4, SYSCALL_ARG5 + }; + + /* wait child stop */ + pid = wait(&status); + if (pid == cpid) { + if (!WIFSTOPPED(status)) { + printf("child is not stopped.\n"); + goto out; + } + } + else { + perror("wait()"); + goto out; + } + + /* rewrite child brk instruction */ + if (rewrite_brk_inst(cpid, &__inst_addr)) { + goto cont; + } + + /* child continue (until next syscall enter) */ + if (ptrace(PTRACE_SYSCALL, cpid, NULL, NULL)) { + perror("ptrace(PTRACE_SYSCALL)"); + goto cont; + } + + /* wait child stop */ + pid = wait(&status); + if (pid == cpid) { + if (!WIFSTOPPED(status)) { + printf("child is not stopped.\n"); + goto out; + } + } + else { + perror("wait()"); + goto out; + } + + /* check syscall arguments */ + for (i = 0; i < sizeof(syscall_args) / + sizeof(syscall_args[0]); i++) { + if (get_check_regs(cpid, i, syscall_args[i]) != 0) { + printf("syscall enter regs[%d] NG.\n", i); + goto out; + } + } + + /* child continue (until syscall exit) */ + if (ptrace(PTRACE_SYSCALL, cpid, NULL, NULL)) { + perror("ptrace(PTRACE_SYSCALL)"); + goto cont; + } + + /* wait child stop */ + pid = wait(&status); + if (pid == cpid) { + if (!WIFSTOPPED(status)) { + printf("child is not stopped.\n"); + goto out; + } + } + else { + perror("wait()"); + goto out; + } + + /* check syscall return */ + if (get_check_regs(cpid, 0, cpid) != 0) { + printf("syscall exit return val NG.\n"); + goto cont; + } + + /* success */ + ret = 0; +cont: + /* child continue */ + if (ptrace(PTRACE_CONT, cpid, NULL, NULL)) { + perror("ptrace(PTRACE_CONT)"); + ret = -1; + } +out: + return ret; +} + +int main(int argc, char *argv[]) +{ + pid_t pid = 0; + int ret = -1; + int func_ret = 0; + int status = 0; + + /* create child process */ + pid = fork(); + + switch (pid) { + case -1: + /* fork() error. */ + perror("fork()"); + goto out; + case 0: + /* child process */ + func_ret = child_func(); + + /* child exit */ + exit(func_ret); + break; + default: + /* parent process */ + func_ret = parent_func(pid); + + /* wait child */ + pid = wait(&status); + if (pid != -1) { + if (WEXITSTATUS(status)) { + printf("WEXITSTATUS() is not 0.\n"); + goto out; + } + } + else { + perror("wait()"); + goto out; + } + + /* parent_func check */ + if (func_ret) { + goto out; + } + break; + } + + /* sccess. */ + ret = 0; +out: + return ret; +} + diff --git a/test/issues/1287/arm64/Makefile b/test/issues/1287/arm64/Makefile new file mode 100644 index 00000000..2dd8b814 --- /dev/null +++ b/test/issues/1287/arm64/Makefile @@ -0,0 +1,10 @@ +# Makefile COPYRIGHT FUJITSU LIMITED 2019 + +all: + $(CC) 1287_arm64.c -o 1287_arm64 + +test: all + ./1287.sh + +clean: + rm -f 1287_arm64 diff --git a/test/issues/1287/arm64/README b/test/issues/1287/arm64/README new file mode 100644 index 00000000..3eb2ee28 --- /dev/null +++ b/test/issues/1287/arm64/README @@ -0,0 +1,30 @@ +/* REDME COPYRIGHT FUJITSU LIMITED 2020 */ + +arm: ptraceでsystem callの返り値を取得できない可能性がある +https://postpeta.pccluster.org/redmine/issues/1287 + +テストセットREADME + +(0) 事前準備 + 1. $HOME/.mck_test_configを用意する + +(1) テスト実行方法 + 1. make test + +(2) テスト項目詳細 + + TEST001: PTRACE_SYSCALLによる停止時、システムコールへの引数および + システムコールからの戻り値がPTRACE_GETREGSETによって獲得できること + + 本修正が既存機能へのレベルダウンとなっていないか確認するため、 + LTPのptraceテストケースについても実施する + - ptrace01,02,03,05 + + なお、本テストの実行は別障害のため、NGとなることがある。 + 別障害は + https://postpeta.pccluster.org/redmine/issues/1451 + https://postpeta.pccluster.org/redmine/issues/1452 + で管理する。 + + +以上。