mirror of
https://github.com/Fishwaldo/linux-bl808.git
synced 2025-03-18 04:54:52 +00:00
selftests/powerpc/ptrace: Add peek/poke of FPRs
Currently the ptrace-gpr test only tests the GET/SET(FP)REGS ptrace
APIs. But there's an alternate (older) API, called PEEK/POKEUSR.
Add some minimal testing of PEEK/POKEUSR of the FPRs. This is sufficient
to detect the bug that was fixed recently in the 32-bit ptrace FPR
handling.
Depends-on: 8e12784444
("powerpc/32: Fix overread/overwrite of thread_struct via ptrace")
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20220627140239.2464900-13-mpe@ellerman.id.au
This commit is contained in:
parent
c5a814cc99
commit
6c9c7d8fbc
2 changed files with 87 additions and 2 deletions
|
@ -46,22 +46,42 @@ static int child(void)
|
|||
|
||||
int trace_gpr(pid_t child)
|
||||
{
|
||||
__u64 tmp, fpr[32], *peeked_fprs;
|
||||
unsigned long gpr[18];
|
||||
__u64 tmp, fpr[32];
|
||||
|
||||
FAIL_IF(start_trace(child));
|
||||
|
||||
// Check child GPRs match what we expect using GETREGS
|
||||
FAIL_IF(show_gpr(child, gpr));
|
||||
FAIL_IF(validate_gpr(gpr, child_gpr_val));
|
||||
FAIL_IF(show_fpr(child, fpr));
|
||||
|
||||
// Check child FPRs match what we expect using GETFPREGS
|
||||
FAIL_IF(show_fpr(child, fpr));
|
||||
memcpy(&tmp, &child_fpr_val, sizeof(tmp));
|
||||
FAIL_IF(validate_fpr(fpr, tmp));
|
||||
|
||||
// Check child FPRs match what we expect using PEEKUSR
|
||||
peeked_fprs = peek_fprs(child);
|
||||
FAIL_IF(!peeked_fprs);
|
||||
FAIL_IF(validate_fpr(peeked_fprs, tmp));
|
||||
free(peeked_fprs);
|
||||
|
||||
// Write child GPRs using SETREGS
|
||||
FAIL_IF(write_gpr(child, parent_gpr_val));
|
||||
|
||||
// Write child FPRs using SETFPREGS
|
||||
memcpy(&tmp, &parent_fpr_val, sizeof(tmp));
|
||||
FAIL_IF(write_fpr(child, tmp));
|
||||
|
||||
// Check child FPRs match what we just set, using PEEKUSR
|
||||
peeked_fprs = peek_fprs(child);
|
||||
FAIL_IF(!peeked_fprs);
|
||||
FAIL_IF(validate_fpr(peeked_fprs, tmp));
|
||||
|
||||
// Write child FPRs using POKEUSR
|
||||
FAIL_IF(poke_fprs(child, (unsigned long *)peeked_fprs));
|
||||
|
||||
// Child will check its FPRs match before exiting
|
||||
FAIL_IF(stop_trace(child));
|
||||
|
||||
return TEST_PASS;
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/user.h>
|
||||
#include <sys/syscall.h>
|
||||
#include <linux/elf.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/auxvec.h>
|
||||
|
@ -440,6 +441,70 @@ int show_gpr(pid_t child, unsigned long *gpr)
|
|||
return TEST_PASS;
|
||||
}
|
||||
|
||||
long sys_ptrace(enum __ptrace_request request, pid_t pid, unsigned long addr, unsigned long data)
|
||||
{
|
||||
return syscall(__NR_ptrace, request, pid, (void *)addr, data);
|
||||
}
|
||||
|
||||
// 33 because of FPSCR
|
||||
#define PT_NUM_FPRS (33 * (sizeof(__u64) / sizeof(unsigned long)))
|
||||
|
||||
__u64 *peek_fprs(pid_t child)
|
||||
{
|
||||
unsigned long *fprs, *p, addr;
|
||||
long ret;
|
||||
int i;
|
||||
|
||||
fprs = malloc(sizeof(unsigned long) * PT_NUM_FPRS);
|
||||
if (!fprs) {
|
||||
perror("malloc() failed");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0, p = fprs; i < PT_NUM_FPRS; i++, p++) {
|
||||
addr = sizeof(unsigned long) * (PT_FPR0 + i);
|
||||
ret = sys_ptrace(PTRACE_PEEKUSER, child, addr, (unsigned long)p);
|
||||
if (ret) {
|
||||
perror("ptrace(PTRACE_PEEKUSR) failed");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
addr = sizeof(unsigned long) * (PT_FPR0 + i);
|
||||
ret = sys_ptrace(PTRACE_PEEKUSER, child, addr, (unsigned long)&addr);
|
||||
if (!ret) {
|
||||
printf("ptrace(PTRACE_PEEKUSR) succeeded unexpectedly!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return (__u64 *)fprs;
|
||||
}
|
||||
|
||||
int poke_fprs(pid_t child, unsigned long *fprs)
|
||||
{
|
||||
unsigned long *p, addr;
|
||||
long ret;
|
||||
int i;
|
||||
|
||||
for (i = 0, p = fprs; i < PT_NUM_FPRS; i++, p++) {
|
||||
addr = sizeof(unsigned long) * (PT_FPR0 + i);
|
||||
ret = sys_ptrace(PTRACE_POKEUSER, child, addr, *p);
|
||||
if (ret) {
|
||||
perror("ptrace(PTRACE_POKEUSR) failed");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
addr = sizeof(unsigned long) * (PT_FPR0 + i);
|
||||
ret = sys_ptrace(PTRACE_POKEUSER, child, addr, addr);
|
||||
if (!ret) {
|
||||
printf("ptrace(PTRACE_POKEUSR) succeeded unexpectedly!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int write_gpr(pid_t child, unsigned long val)
|
||||
{
|
||||
struct pt_regs *regs;
|
||||
|
|
Loading…
Add table
Reference in a new issue