![Zachary Amsden](/assets/img/avatar_default.png)
Profile_pc was broken when using paravirtualization because the assumption the kernel was running at CPL 0 was violated, causing bad logic to read a random value off the stack. The only way to be in kernel lock functions is to be in kernel code, so validate that assumption explicitly by checking the CS value. We don't want to be fooled by BIOS / APM segments and try to read those stacks, so only match KERNEL_CS. I moved some stuff in segment.h to make it prettier. Signed-off-by: Zachary Amsden <zach@vmware.com> Signed-off-by: Andi Kleen <ak@suse.de>
64 lines
1.4 KiB
C
64 lines
1.4 KiB
C
#ifndef _I386_PTRACE_H
|
|
#define _I386_PTRACE_H
|
|
|
|
#include <asm/ptrace-abi.h>
|
|
|
|
/* this struct defines the way the registers are stored on the
|
|
stack during a system call. */
|
|
|
|
struct pt_regs {
|
|
long ebx;
|
|
long ecx;
|
|
long edx;
|
|
long esi;
|
|
long edi;
|
|
long ebp;
|
|
long eax;
|
|
int xds;
|
|
int xes;
|
|
int xfs;
|
|
/* int xgs; */
|
|
long orig_eax;
|
|
long eip;
|
|
int xcs;
|
|
long eflags;
|
|
long esp;
|
|
int xss;
|
|
};
|
|
|
|
#ifdef __KERNEL__
|
|
|
|
#include <asm/vm86.h>
|
|
#include <asm/segment.h>
|
|
|
|
struct task_struct;
|
|
extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code);
|
|
|
|
/*
|
|
* user_mode_vm(regs) determines whether a register set came from user mode.
|
|
* This is true if V8086 mode was enabled OR if the register set was from
|
|
* protected mode with RPL-3 CS value. This tricky test checks that with
|
|
* one comparison. Many places in the kernel can bypass this full check
|
|
* if they have already ruled out V8086 mode, so user_mode(regs) can be used.
|
|
*/
|
|
static inline int user_mode(struct pt_regs *regs)
|
|
{
|
|
return (regs->xcs & SEGMENT_RPL_MASK) == USER_RPL;
|
|
}
|
|
static inline int user_mode_vm(struct pt_regs *regs)
|
|
{
|
|
return ((regs->xcs & SEGMENT_RPL_MASK) | (regs->eflags & VM_MASK)) >= USER_RPL;
|
|
}
|
|
static inline int v8086_mode(struct pt_regs *regs)
|
|
{
|
|
return (regs->eflags & VM_MASK);
|
|
}
|
|
|
|
#define instruction_pointer(regs) ((regs)->eip)
|
|
#define regs_return_value(regs) ((regs)->eax)
|
|
|
|
extern unsigned long profile_pc(struct pt_regs *regs);
|
|
#endif /* __KERNEL__ */
|
|
|
|
#endif
|