Implement PTRACE_GET_SYSCALL_INFO decoder
* defs.h (audit_arch): New prototype. * process.c: Include "ptrace_syscall_info.h". (SYS_FUNC(ptrace)) <PTRACE_GET_SYSCALL_INFO>: Call print_ptrace_syscall_info on exiting syscall. * ptrace_syscall_info.h (print_ptrace_syscall_info): New prototype. * ptrace_syscall_info.c: Include "print_fields.h" and "xlat/ptrace_syscall_info_op.h". (print_ptrace_syscall_info): New function. * xlat/ptrace_syscall_info_op.in: New file. * tests/ptrace_syscall_info.c: New file. * tests/gen_tests.in (ptrace_syscall_info): New test. * tests/pure_executables.list: Add ptrace_syscall_info. * tests/.gitignore: Likewise.
This commit is contained in:
parent
e3b80cb65f
commit
7273c6fb3c
1
defs.h
1
defs.h
@ -312,6 +312,7 @@ extern const struct xlat evdev_abs[];
|
||||
/** Number of elements in evdev_abs array without the terminating record. */
|
||||
extern const size_t evdev_abs_size;
|
||||
|
||||
extern const struct xlat audit_arch[];
|
||||
extern const struct xlat evdev_ev[];
|
||||
extern const struct xlat iffflags[];
|
||||
extern const struct xlat ip_type_of_services[];
|
||||
|
@ -22,6 +22,7 @@
|
||||
#endif
|
||||
|
||||
#include "ptrace.h"
|
||||
#include "ptrace_syscall_info.h"
|
||||
#include "regs.h"
|
||||
|
||||
#include "xlat/nt_descriptor_types.h"
|
||||
@ -220,6 +221,7 @@ SYS_FUNC(ptrace)
|
||||
case PTRACE_GETSIGMASK:
|
||||
case PTRACE_PEEKSIGINFO:
|
||||
case PTRACE_SECCOMP_GET_FILTER:
|
||||
case PTRACE_GET_SYSCALL_INFO:
|
||||
if (verbose(tcp)) {
|
||||
/* print data on exiting syscall */
|
||||
return 0;
|
||||
@ -283,7 +285,11 @@ SYS_FUNC(ptrace)
|
||||
tprints(", ...");
|
||||
|
||||
tprints("}");
|
||||
break;
|
||||
}
|
||||
case PTRACE_GET_SYSCALL_INFO:
|
||||
print_ptrace_syscall_info(tcp, data, addr);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -7,6 +7,7 @@
|
||||
|
||||
#include "defs.h"
|
||||
#include "kill_save_errno.h"
|
||||
#include "print_fields.h"
|
||||
#include "ptrace.h"
|
||||
#include "ptrace_syscall_info.h"
|
||||
#include "scno.h"
|
||||
@ -14,6 +15,8 @@
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
#include "xlat/ptrace_syscall_info_op.h"
|
||||
|
||||
bool ptrace_get_syscall_info_supported;
|
||||
|
||||
static int
|
||||
@ -30,6 +33,8 @@ static const unsigned int expected_entry_size =
|
||||
offsetofend(struct ptrace_syscall_info, entry.args);
|
||||
static const unsigned int expected_exit_size =
|
||||
offsetofend(struct ptrace_syscall_info, exit.is_error);
|
||||
static const unsigned int expected_seccomp_size =
|
||||
offsetofend(struct ptrace_syscall_info, seccomp.ret_data);
|
||||
|
||||
/*
|
||||
* Test that PTRACE_GET_SYSCALL_INFO API is supported by the kernel, and
|
||||
@ -250,3 +255,84 @@ done:
|
||||
|
||||
return ptrace_get_syscall_info_supported;
|
||||
}
|
||||
|
||||
void
|
||||
print_ptrace_syscall_info(struct tcb *tcp, kernel_ulong_t addr,
|
||||
kernel_ulong_t user_len)
|
||||
{
|
||||
struct ptrace_syscall_info info;
|
||||
kernel_ulong_t kernel_len = tcp->u_rval;
|
||||
kernel_ulong_t ret_len = MIN(user_len, kernel_len);
|
||||
kernel_ulong_t fetch_size = MIN(ret_len, expected_seccomp_size);
|
||||
|
||||
if (!fetch_size || !tfetch_mem(tcp, addr, fetch_size, &info)) {
|
||||
printaddr(addr);
|
||||
return;
|
||||
}
|
||||
|
||||
PRINT_FIELD_XVAL_INDEX("{", info, op, ptrace_syscall_info_op,
|
||||
"PTRACE_SYSCALL_INFO_???");
|
||||
if (fetch_size < offsetofend(struct ptrace_syscall_info, arch))
|
||||
goto printed;
|
||||
PRINT_FIELD_XVAL(", ", info, arch, audit_arch, "AUDIT_ARCH_???");
|
||||
|
||||
if (fetch_size < offsetofend(struct ptrace_syscall_info,
|
||||
instruction_pointer))
|
||||
goto printed;
|
||||
PRINT_FIELD_ADDR64(", ", info, instruction_pointer);
|
||||
|
||||
if (fetch_size < offsetofend(struct ptrace_syscall_info, stack_pointer))
|
||||
goto printed;
|
||||
PRINT_FIELD_ADDR64(", ", info, stack_pointer);
|
||||
|
||||
if (fetch_size < offsetofend(struct ptrace_syscall_info, entry.nr))
|
||||
goto printed;
|
||||
|
||||
switch(info.op) {
|
||||
case PTRACE_SYSCALL_INFO_ENTRY:
|
||||
case PTRACE_SYSCALL_INFO_SECCOMP:
|
||||
PRINT_FIELD_U((info.op == PTRACE_SYSCALL_INFO_ENTRY
|
||||
? ", entry={" : ", seccomp={"),
|
||||
info.entry, nr);
|
||||
for (unsigned int i = 0;
|
||||
i < ARRAY_SIZE(info.entry.args); ++i) {
|
||||
const unsigned int i_size =
|
||||
offsetofend(struct ptrace_syscall_info,
|
||||
entry.args[i]);
|
||||
if (fetch_size < i_size) {
|
||||
if (i)
|
||||
break;
|
||||
goto entry_printed;
|
||||
}
|
||||
tprintf(", %s%#" PRIx64,
|
||||
(i ? "" : "arg=["),
|
||||
(uint64_t) info.entry.args[i]);
|
||||
}
|
||||
tprints("]");
|
||||
if (info.op == PTRACE_SYSCALL_INFO_SECCOMP
|
||||
&& fetch_size >= expected_seccomp_size)
|
||||
PRINT_FIELD_U(", ", info.seccomp, ret_data);
|
||||
entry_printed:
|
||||
tprints("}");
|
||||
break;
|
||||
case PTRACE_SYSCALL_INFO_EXIT:
|
||||
tprints(", exit={");
|
||||
if (fetch_size >= expected_exit_size
|
||||
&& info.exit.is_error) {
|
||||
uint64_t err = -info.exit.rval;
|
||||
|
||||
tprints("rval=-");
|
||||
print_xlat_ex(err, err_name(err),
|
||||
XLAT_STYLE_FMT_U);
|
||||
} else {
|
||||
PRINT_FIELD_D("", info.exit, rval);
|
||||
}
|
||||
if (fetch_size >= expected_exit_size)
|
||||
PRINT_FIELD_U(", ", info.exit, is_error);
|
||||
tprints("}");
|
||||
break;
|
||||
}
|
||||
|
||||
printed:
|
||||
tprints("}");
|
||||
}
|
||||
|
@ -10,5 +10,7 @@
|
||||
|
||||
extern bool ptrace_get_syscall_info_supported;
|
||||
extern bool test_ptrace_get_syscall_info(void);
|
||||
extern void print_ptrace_syscall_info(struct tcb *, kernel_ulong_t addr,
|
||||
kernel_ulong_t len);
|
||||
|
||||
#endif /* !STRACE_PTRACE_SYSCALL_INFO_H */
|
||||
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -400,6 +400,7 @@ process_vm_readv
|
||||
process_vm_writev
|
||||
pselect6
|
||||
ptrace
|
||||
ptrace_syscall_info
|
||||
pure_executables.am
|
||||
pwritev
|
||||
qual_fault
|
||||
|
@ -332,6 +332,7 @@ process_vm_readv -s5 -a37
|
||||
process_vm_writev -s5 -a38
|
||||
pselect6
|
||||
ptrace -a23 -e signal=none
|
||||
ptrace_syscall_info -a35 -e signal=none -e trace=ptrace
|
||||
pwritev -a22 -s7
|
||||
quotactl
|
||||
quotactl-v -v -e trace=quotactl
|
||||
|
460
tests/ptrace_syscall_info.c
Normal file
460
tests/ptrace_syscall_info.c
Normal file
@ -0,0 +1,460 @@
|
||||
/*
|
||||
* Check decoding of ptrace PTRACE_GET_SYSCALL_INFO request.
|
||||
*
|
||||
* Copyright (c) 2018 Dmitry V. Levin <ldv@altlinux.org>
|
||||
* All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "tests.h"
|
||||
|
||||
#include "ptrace.h"
|
||||
#include <asm/unistd.h>
|
||||
#include "scno.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stddef.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <signal.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
#include <linux/audit.h>
|
||||
|
||||
#include "xlat.h"
|
||||
#include "xlat/audit_arch.h"
|
||||
|
||||
static const char *errstr;
|
||||
|
||||
static long
|
||||
do_ptrace(unsigned long request, unsigned long pid,
|
||||
unsigned long addr, unsigned long data)
|
||||
{
|
||||
long rc = syscall(__NR_ptrace, request, pid, addr, data);
|
||||
errstr = sprintrc(rc);
|
||||
return rc;
|
||||
}
|
||||
|
||||
static pid_t pid;
|
||||
|
||||
static void
|
||||
kill_tracee(void)
|
||||
{
|
||||
if (!pid)
|
||||
return;
|
||||
int saved_errno = errno;
|
||||
kill(pid, SIGKILL);
|
||||
errno = saved_errno;
|
||||
}
|
||||
|
||||
#define FAIL(fmt_, ...) \
|
||||
do { \
|
||||
kill_tracee(); \
|
||||
error_msg_and_fail("%s:%d: " fmt_, \
|
||||
__FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
#define PFAIL(fmt_, ...) \
|
||||
do { \
|
||||
kill_tracee(); \
|
||||
perror_msg_and_fail("%s:%d: " fmt_, \
|
||||
__FILE__, __LINE__, ##__VA_ARGS__); \
|
||||
} while (0)
|
||||
|
||||
static const unsigned long args[][7] = {
|
||||
/* a sequence of architecture-agnostic syscalls */
|
||||
{
|
||||
__NR_chdir,
|
||||
(unsigned long) "",
|
||||
0xbad1fed1,
|
||||
0xbad2fed2,
|
||||
0xbad3fed3,
|
||||
0xbad4fed4,
|
||||
0xbad5fed5
|
||||
},
|
||||
{
|
||||
__NR_gettid,
|
||||
0xcaf0bea0,
|
||||
0xcaf1bea1,
|
||||
0xcaf2bea2,
|
||||
0xcaf3bea3,
|
||||
0xcaf4bea4,
|
||||
0xcaf5bea5
|
||||
},
|
||||
{
|
||||
__NR_exit_group,
|
||||
0,
|
||||
0xfac1c0d1,
|
||||
0xfac2c0d2,
|
||||
0xfac3c0d3,
|
||||
0xfac4c0d4,
|
||||
0xfac5c0d5
|
||||
}
|
||||
};
|
||||
|
||||
static const unsigned int expected_none_size =
|
||||
offsetof(struct ptrace_syscall_info, entry);
|
||||
static const unsigned int expected_entry_size =
|
||||
offsetofend(struct ptrace_syscall_info, entry.args);
|
||||
static const unsigned int expected_exit_size =
|
||||
offsetofend(struct ptrace_syscall_info, exit.is_error);
|
||||
|
||||
static unsigned long end_of_page;
|
||||
static unsigned int ptrace_stop;
|
||||
|
||||
static bool
|
||||
test_none(void)
|
||||
{
|
||||
do_ptrace(PTRACE_GET_SYSCALL_INFO, pid, 1, 0);
|
||||
printf("ptrace(PTRACE_GET_SYSCALL_INFO, %d, 1, NULL) = %s\n",
|
||||
pid, errstr);
|
||||
|
||||
do_ptrace(PTRACE_GET_SYSCALL_INFO, pid, 1, end_of_page);
|
||||
printf("ptrace(PTRACE_GET_SYSCALL_INFO, %d, 1, %#lx) = %s\n",
|
||||
pid, end_of_page, errstr);
|
||||
|
||||
for (unsigned int size = 0;
|
||||
size <= sizeof(struct ptrace_syscall_info); ++size) {
|
||||
unsigned long buf = end_of_page - size;
|
||||
memset((void *) buf, -1, size);
|
||||
|
||||
long rc = do_ptrace(PTRACE_GET_SYSCALL_INFO, pid, size, buf);
|
||||
if (rc < 0) {
|
||||
printf("ptrace(PTRACE_GET_SYSCALL_INFO, %d, %u, %#lx)"
|
||||
" = %s\n",
|
||||
pid, (unsigned int) size, buf, errstr);
|
||||
return false;
|
||||
}
|
||||
if (rc < (long) expected_none_size)
|
||||
FAIL("signal stop mismatch");
|
||||
|
||||
printf("ptrace(PTRACE_GET_SYSCALL_INFO, %d, %u, ",
|
||||
pid, size);
|
||||
if (!size) {
|
||||
printf("%#lx) = %s\n", buf, errstr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy to a local structure to avoid unaligned access */
|
||||
struct ptrace_syscall_info info;
|
||||
memcpy(&info, (void *) buf, MIN(size, expected_none_size));
|
||||
|
||||
if (info.op != PTRACE_SYSCALL_INFO_NONE)
|
||||
FAIL("signal stop mismatch");
|
||||
printf("{op=PTRACE_SYSCALL_INFO_NONE");
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info, arch))
|
||||
goto printed_none;
|
||||
if (!info.arch)
|
||||
FAIL("signal stop mismatch");
|
||||
printf(", arch=");
|
||||
printxval(audit_arch, info.arch, "AUDIT_ARCH_???");
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info,
|
||||
instruction_pointer))
|
||||
goto printed_none;
|
||||
if (!info.instruction_pointer)
|
||||
FAIL("signal stop mismatch");
|
||||
printf(", instruction_pointer=%#llx",
|
||||
(unsigned long long) info.instruction_pointer);
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info,
|
||||
stack_pointer))
|
||||
goto printed_none;
|
||||
if (!info.stack_pointer)
|
||||
FAIL("signal stop mismatch");
|
||||
printf(", stack_pointer=%#llx",
|
||||
(unsigned long long) info.stack_pointer);
|
||||
|
||||
printed_none:
|
||||
printf("}) = %s\n", errstr);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void
|
||||
test_entry(void)
|
||||
{
|
||||
for (unsigned int size = 0;
|
||||
size <= sizeof(struct ptrace_syscall_info); ++size) {
|
||||
unsigned long buf = end_of_page - size;
|
||||
memset((void *) buf, -1, size);
|
||||
|
||||
long rc = do_ptrace(PTRACE_GET_SYSCALL_INFO, pid, size, buf);
|
||||
if (rc < 0)
|
||||
PFAIL("PTRACE_GET_SYSCALL_INFO");
|
||||
|
||||
if (rc < (long) expected_entry_size)
|
||||
FAIL("#%d: entry stop mismatch", ptrace_stop);
|
||||
|
||||
printf("ptrace(PTRACE_GET_SYSCALL_INFO, %d, %u, ",
|
||||
pid, size);
|
||||
if (!size) {
|
||||
printf("%#lx) = %s\n", buf, errstr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy to a local structure to avoid unaligned access */
|
||||
struct ptrace_syscall_info info;
|
||||
memcpy(&info, (void *) buf, MIN(size, expected_entry_size));
|
||||
|
||||
if (info.op != PTRACE_SYSCALL_INFO_ENTRY)
|
||||
FAIL("#%d: entry stop mismatch", ptrace_stop);
|
||||
printf("{op=PTRACE_SYSCALL_INFO_ENTRY");
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info, arch))
|
||||
goto printed_entry_common;
|
||||
if (!info.arch)
|
||||
FAIL("#%d: entry stop mismatch", ptrace_stop);
|
||||
printf(", arch=");
|
||||
printxval(audit_arch, info.arch, "AUDIT_ARCH_???");
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info,
|
||||
instruction_pointer))
|
||||
goto printed_entry_common;
|
||||
if (!info.instruction_pointer)
|
||||
FAIL("#%d: entry stop mismatch", ptrace_stop);
|
||||
printf(", instruction_pointer=%#llx",
|
||||
(unsigned long long) info.instruction_pointer);
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info,
|
||||
stack_pointer))
|
||||
goto printed_entry_common;
|
||||
if (!info.stack_pointer)
|
||||
FAIL("#%d: entry stop mismatch", ptrace_stop);
|
||||
printf(", stack_pointer=%#llx",
|
||||
(unsigned long long) info.stack_pointer);
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info, entry.nr))
|
||||
goto printed_entry_common;
|
||||
const unsigned long *exp_args = args[ptrace_stop / 2];
|
||||
if (info.entry.nr != exp_args[0])
|
||||
FAIL("#%d: entry stop mismatch", ptrace_stop);
|
||||
printf(", entry={nr=%llu", (unsigned long long) info.entry.nr);
|
||||
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(info.entry.args); ++i) {
|
||||
const unsigned int i_size =
|
||||
offsetofend(struct ptrace_syscall_info,
|
||||
entry.args[i]);
|
||||
if (size < i_size) {
|
||||
if (i)
|
||||
break;
|
||||
goto printed_entry_nr;
|
||||
}
|
||||
if (info.entry.args[i] != exp_args[i + 1])
|
||||
FAIL("#%d: entry stop mismatch", ptrace_stop);
|
||||
printf("%s%#llx", (i ? ", " : ", arg=["),
|
||||
(unsigned long long) info.entry.args[i]);
|
||||
}
|
||||
printf("]");
|
||||
|
||||
printed_entry_nr:
|
||||
printf("}");
|
||||
|
||||
printed_entry_common:
|
||||
printf("}) = %s\n", errstr);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
test_exit(void)
|
||||
{
|
||||
for (unsigned int size = 0;
|
||||
size <= sizeof(struct ptrace_syscall_info); ++size) {
|
||||
unsigned long buf = end_of_page - size;
|
||||
memset((void *) buf, -1, size);
|
||||
|
||||
long rc = do_ptrace(PTRACE_GET_SYSCALL_INFO, pid, size, buf);
|
||||
if (rc < 0)
|
||||
PFAIL("PTRACE_GET_SYSCALL_INFO");
|
||||
|
||||
if (rc < (long) expected_exit_size)
|
||||
FAIL("#%d: exit stop mismatch", ptrace_stop);
|
||||
|
||||
printf("ptrace(PTRACE_GET_SYSCALL_INFO, %d, %u, ",
|
||||
pid, size);
|
||||
if (!size) {
|
||||
printf("%#lx) = %s\n", buf, errstr);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* copy to a local structure to avoid unaligned access */
|
||||
struct ptrace_syscall_info info;
|
||||
memcpy(&info, (void *) buf, MIN(size, expected_exit_size));
|
||||
|
||||
if (info.op != PTRACE_SYSCALL_INFO_EXIT)
|
||||
FAIL("#%d: exit stop mismatch", ptrace_stop);
|
||||
printf("{op=PTRACE_SYSCALL_INFO_EXIT");
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info, arch))
|
||||
goto printed_exit_common;
|
||||
if (!info.arch)
|
||||
FAIL("#%d: exit stop mismatch", ptrace_stop);
|
||||
printf(", arch=");
|
||||
printxval(audit_arch, info.arch, "AUDIT_ARCH_???");
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info,
|
||||
instruction_pointer))
|
||||
goto printed_exit_common;
|
||||
if (!info.instruction_pointer)
|
||||
FAIL("#%d: exit stop mismatch", ptrace_stop);
|
||||
printf(", instruction_pointer=%#llx",
|
||||
(unsigned long long) info.instruction_pointer);
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info,
|
||||
stack_pointer))
|
||||
goto printed_exit_common;
|
||||
if (!info.stack_pointer)
|
||||
FAIL("#%d: exit stop mismatch", ptrace_stop);
|
||||
printf(", stack_pointer=%#llx",
|
||||
(unsigned long long) info.stack_pointer);
|
||||
|
||||
const struct {
|
||||
unsigned int is_error;
|
||||
int rval;
|
||||
const char *str;
|
||||
} exit_param[] = {
|
||||
{ 1, -ENOENT, "-ENOENT" }, /* chdir */
|
||||
{ 0, pid, NULL } /* gettid */
|
||||
}, *exp_param = &exit_param[ptrace_stop / 2 - 1];
|
||||
|
||||
if (size < offsetofend(struct ptrace_syscall_info, exit.rval))
|
||||
goto printed_exit_common;
|
||||
if (info.exit.rval != exp_param->rval)
|
||||
FAIL("#%d: exit stop mismatch", ptrace_stop);
|
||||
if (size >= expected_exit_size && info.exit.is_error) {
|
||||
printf(", exit={rval=%s", exp_param->str);
|
||||
} else {
|
||||
printf(", exit={rval=%lld", (long long) info.exit.rval);
|
||||
}
|
||||
|
||||
if (size >= expected_exit_size) {
|
||||
if (info.exit.is_error != exp_param->is_error)
|
||||
FAIL("#%d: exit stop mismatch", ptrace_stop);
|
||||
printf(", is_error=%u",
|
||||
(unsigned int) info.exit.is_error);
|
||||
}
|
||||
|
||||
printf("}");
|
||||
|
||||
printed_exit_common:
|
||||
printf("}) = %s\n", errstr);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main(void)
|
||||
{
|
||||
end_of_page = (unsigned long) tail_alloc(1) + 1;
|
||||
|
||||
pid = getpid();
|
||||
do_ptrace(PTRACE_GET_SYSCALL_INFO, pid, 0, 0);
|
||||
printf("ptrace(PTRACE_GET_SYSCALL_INFO, %d, 0, NULL) = %s\n",
|
||||
pid, errstr);
|
||||
|
||||
pid = fork();
|
||||
if (pid < 0)
|
||||
PFAIL("fork");
|
||||
|
||||
if (pid == 0) {
|
||||
/* get the pid before PTRACE_TRACEME */
|
||||
pid = getpid();
|
||||
if (do_ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) {
|
||||
/* exit with a nonzero exit status */
|
||||
PFAIL("PTRACE_TRACEME");
|
||||
}
|
||||
kill(pid, SIGSTOP);
|
||||
for (unsigned int i = 0; i < ARRAY_SIZE(args); ++i) {
|
||||
syscall(args[i][0],
|
||||
args[i][1], args[i][2], args[i][3],
|
||||
args[i][4], args[i][5], args[i][6]);
|
||||
}
|
||||
/* unreachable */
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
for (ptrace_stop = 0; ; ++ptrace_stop) {
|
||||
int status;
|
||||
long rc = waitpid(pid, &status, 0);
|
||||
if (rc != pid) {
|
||||
/* cannot happen */
|
||||
PFAIL("#%d: unexpected wait result %ld",
|
||||
ptrace_stop, rc);
|
||||
}
|
||||
if (WIFEXITED(status)) {
|
||||
/* tracee is no more */
|
||||
pid = 0;
|
||||
if (WEXITSTATUS(status) == 0)
|
||||
break;
|
||||
FAIL("#%d: unexpected exit status %u",
|
||||
ptrace_stop, WEXITSTATUS(status));
|
||||
}
|
||||
if (WIFSIGNALED(status)) {
|
||||
/* tracee is no more */
|
||||
pid = 0;
|
||||
FAIL("#%d: unexpected signal %u",
|
||||
ptrace_stop, WTERMSIG(status));
|
||||
}
|
||||
if (!WIFSTOPPED(status)) {
|
||||
/* cannot happen */
|
||||
FAIL("#%d: unexpected wait status %#x",
|
||||
ptrace_stop, status);
|
||||
}
|
||||
|
||||
switch (WSTOPSIG(status)) {
|
||||
case SIGSTOP:
|
||||
if (ptrace_stop)
|
||||
FAIL("#%d: unexpected signal stop",
|
||||
ptrace_stop);
|
||||
if (do_ptrace(PTRACE_SETOPTIONS, pid, 0,
|
||||
PTRACE_O_TRACESYSGOOD) < 0) {
|
||||
/* cannot happen */
|
||||
PFAIL("PTRACE_SETOPTIONS");
|
||||
}
|
||||
printf("ptrace(PTRACE_SETOPTIONS, %d, NULL"
|
||||
", PTRACE_O_TRACESYSGOOD) = 0\n", pid);
|
||||
|
||||
if (!test_none())
|
||||
goto done;
|
||||
break;
|
||||
|
||||
case SIGTRAP | 0x80:
|
||||
switch (ptrace_stop) {
|
||||
case 1: /* entering chdir */
|
||||
case 3: /* entering gettid */
|
||||
case 5: /* entering exit_group */
|
||||
test_entry();
|
||||
break;
|
||||
case 2: /* exiting chdir */
|
||||
case 4: /* exiting gettid */
|
||||
test_exit();
|
||||
break;
|
||||
default:
|
||||
FAIL("#%d: unexpected syscall stop",
|
||||
ptrace_stop);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
FAIL("#%d: unexpected stop signal %#x",
|
||||
ptrace_stop, WSTOPSIG(status));
|
||||
}
|
||||
|
||||
if (do_ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) {
|
||||
/* cannot happen */
|
||||
PFAIL("PTRACE_SYSCALL");
|
||||
}
|
||||
printf("ptrace(PTRACE_SYSCALL, %d, NULL, 0) = 0\n", pid);
|
||||
}
|
||||
|
||||
done:
|
||||
if (pid) {
|
||||
kill_tracee();
|
||||
waitpid(pid, NULL, 0);
|
||||
}
|
||||
|
||||
puts("+++ exited with 0 +++");
|
||||
return 0;
|
||||
}
|
@ -336,6 +336,7 @@ process_vm_readv
|
||||
process_vm_writev
|
||||
pselect6
|
||||
ptrace
|
||||
ptrace_syscall_info
|
||||
pwritev
|
||||
quotactl
|
||||
quotactl-xfs
|
||||
|
5
xlat/ptrace_syscall_info_op.in
Normal file
5
xlat/ptrace_syscall_info_op.in
Normal file
@ -0,0 +1,5 @@
|
||||
#value_indexed
|
||||
PTRACE_SYSCALL_INFO_NONE
|
||||
PTRACE_SYSCALL_INFO_ENTRY
|
||||
PTRACE_SYSCALL_INFO_EXIT
|
||||
PTRACE_SYSCALL_INFO_SECCOMP
|
Loading…
Reference in New Issue
Block a user