test: ptrace: Record syscall return value before reporting
Change-Id: I8e9de3bb9bfa0b07eebe472131cc62b53ef5cc8b Refs: #1287
This commit is contained in:
committed by
Masamichi Takagi
parent
7c69cfaf67
commit
33cba1ad48
42
test/issues/1287/arm64/1287.sh
Executable file
42
test/issues/1287/arm64/1287.sh
Executable file
@ -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
|
||||
259
test/issues/1287/arm64/1287_arm64.c
Normal file
259
test/issues/1287/arm64/1287_arm64.c
Normal file
@ -0,0 +1,259 @@
|
||||
/* 1287_arm64.c COPYRIGHT FUJITSU LIMITED 2019 */
|
||||
/* ptrace(PTRACE_SYSCALL) args and ret check testcase */
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <sys/ptrace.h>
|
||||
#include <errno.h>
|
||||
#include <sys/uio.h>
|
||||
#include <asm/ptrace.h>
|
||||
#include <linux/elf.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
10
test/issues/1287/arm64/Makefile
Normal file
10
test/issues/1287/arm64/Makefile
Normal file
@ -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
|
||||
30
test/issues/1287/arm64/README
Normal file
30
test/issues/1287/arm64/README
Normal file
@ -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
|
||||
で管理する。
|
||||
|
||||
|
||||
以上。
|
||||
Reference in New Issue
Block a user