Merge branch 'x86-ptrace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip
* 'x86-ptrace-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/linux-2.6-tip: x86, ptrace: Remove set_stopped_child_used_math() in [x]fpregs_set x86, ptrace: Simplify xstateregs_get() ptrace: Fix ptrace_regset() comments and diagnose errors specifically parisc: Disable CONFIG_HAVE_ARCH_TRACEHOOK ptrace: Add support for generic PTRACE_GETREGSET/PTRACE_SETREGSET x86, ptrace: regset extensions to support xstate
This commit is contained in:
@@ -22,6 +22,7 @@
|
||||
#include <linux/pid_namespace.h>
|
||||
#include <linux/syscalls.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/regset.h>
|
||||
|
||||
|
||||
/*
|
||||
@@ -511,6 +512,47 @@ static int ptrace_resume(struct task_struct *child, long request, long data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
|
||||
|
||||
static const struct user_regset *
|
||||
find_regset(const struct user_regset_view *view, unsigned int type)
|
||||
{
|
||||
const struct user_regset *regset;
|
||||
int n;
|
||||
|
||||
for (n = 0; n < view->n; ++n) {
|
||||
regset = view->regsets + n;
|
||||
if (regset->core_note_type == type)
|
||||
return regset;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int ptrace_regset(struct task_struct *task, int req, unsigned int type,
|
||||
struct iovec *kiov)
|
||||
{
|
||||
const struct user_regset_view *view = task_user_regset_view(task);
|
||||
const struct user_regset *regset = find_regset(view, type);
|
||||
int regset_no;
|
||||
|
||||
if (!regset || (kiov->iov_len % regset->size) != 0)
|
||||
return -EINVAL;
|
||||
|
||||
regset_no = regset - view->regsets;
|
||||
kiov->iov_len = min(kiov->iov_len,
|
||||
(__kernel_size_t) (regset->n * regset->size));
|
||||
|
||||
if (req == PTRACE_GETREGSET)
|
||||
return copy_regset_to_user(task, view, regset_no, 0,
|
||||
kiov->iov_len, kiov->iov_base);
|
||||
else
|
||||
return copy_regset_from_user(task, view, regset_no, 0,
|
||||
kiov->iov_len, kiov->iov_base);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int ptrace_request(struct task_struct *child, long request,
|
||||
long addr, long data)
|
||||
{
|
||||
@@ -573,6 +615,26 @@ int ptrace_request(struct task_struct *child, long request,
|
||||
return 0;
|
||||
return ptrace_resume(child, request, SIGKILL);
|
||||
|
||||
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
|
||||
case PTRACE_GETREGSET:
|
||||
case PTRACE_SETREGSET:
|
||||
{
|
||||
struct iovec kiov;
|
||||
struct iovec __user *uiov = (struct iovec __user *) data;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov)))
|
||||
return -EFAULT;
|
||||
|
||||
if (__get_user(kiov.iov_base, &uiov->iov_base) ||
|
||||
__get_user(kiov.iov_len, &uiov->iov_len))
|
||||
return -EFAULT;
|
||||
|
||||
ret = ptrace_regset(child, request, addr, &kiov);
|
||||
if (!ret)
|
||||
ret = __put_user(kiov.iov_len, &uiov->iov_len);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -711,6 +773,32 @@ int compat_ptrace_request(struct task_struct *child, compat_long_t request,
|
||||
else
|
||||
ret = ptrace_setsiginfo(child, &siginfo);
|
||||
break;
|
||||
#ifdef CONFIG_HAVE_ARCH_TRACEHOOK
|
||||
case PTRACE_GETREGSET:
|
||||
case PTRACE_SETREGSET:
|
||||
{
|
||||
struct iovec kiov;
|
||||
struct compat_iovec __user *uiov =
|
||||
(struct compat_iovec __user *) datap;
|
||||
compat_uptr_t ptr;
|
||||
compat_size_t len;
|
||||
|
||||
if (!access_ok(VERIFY_WRITE, uiov, sizeof(*uiov)))
|
||||
return -EFAULT;
|
||||
|
||||
if (__get_user(ptr, &uiov->iov_base) ||
|
||||
__get_user(len, &uiov->iov_len))
|
||||
return -EFAULT;
|
||||
|
||||
kiov.iov_base = compat_ptr(ptr);
|
||||
kiov.iov_len = len;
|
||||
|
||||
ret = ptrace_regset(child, request, addr, &kiov);
|
||||
if (!ret)
|
||||
ret = __put_user(kiov.iov_len, &uiov->iov_len);
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
default:
|
||||
ret = ptrace_request(child, request, addr, data);
|
||||
|
||||
Reference in New Issue
Block a user