Messages in this thread Patch in this message | | | From | "Chang S. Bae" <> | Subject | [PATCH 06/15] x86/fsgsbase/64: Add putregs() to handle multiple elements' setting | Date | Mon, 19 Mar 2018 10:49:18 -0700 |
| |
putregs() can be used to handle multiple elements flexibly.
It is useful when inter-dependency lies in updating a group of context entries. There will be a case with FSGSBASE.
Signed-off-by: Chang S. Bae <chang.seok.bae@intel.com> Cc: Markus T. Metzger <markus.t.metzger@intel.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Andi Kleen <ak@linux.intel.com> Cc: Andy Lutomirski <luto@kernel.org> --- arch/x86/kernel/ptrace.c | 51 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 40 insertions(+), 11 deletions(-)
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index d8a1e1b..9c09bf0 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c @@ -421,6 +421,22 @@ static int putreg(struct task_struct *child, return 0; } +static int putregs(struct task_struct *child, + unsigned int offset, + unsigned int count, + const unsigned long *values) +{ + const unsigned long *v = values; + int ret = 0; + + while (count >= sizeof(*v) && !ret) { + ret = putreg(child, offset, *v++); + count -= sizeof(*v); + offset += sizeof(*v); + } + return ret; +} + static unsigned long getreg(struct task_struct *task, unsigned long offset) { switch (offset) { @@ -477,24 +493,37 @@ static int genregs_set(struct task_struct *target, const void *kbuf, const void __user *ubuf) { int ret = 0; + if (kbuf) { - const unsigned long *k = kbuf; - while (count >= sizeof(*k) && !ret) { - ret = putreg(target, pos, *k++); - count -= sizeof(*k); - pos += sizeof(*k); - } + ret = putregs(target, pos, count, kbuf); } else { const unsigned long __user *u = ubuf; - while (count >= sizeof(*u) && !ret) { + const unsigned long *genregs = NULL; + unsigned long *buf = NULL; + unsigned int remains = 0; + + buf = kmalloc(count, GFP_KERNEL); + + if (unlikely(!buf)) + return -ENOMEM; + + genregs = buf; + remains = count; + + while (remains >= sizeof(*u) && !ret) { unsigned long word; + ret = __get_user(word, u++); - if (ret) + if (unlikely(ret)) break; - ret = putreg(target, pos, word); - count -= sizeof(*u); - pos += sizeof(*u); + memcpy(buf++, &word, sizeof(*u)); + remains -= sizeof(*u); } + + if (likely(!ret)) + /* Allows to handle multiple elements accordingly. */ + ret = putregs(target, pos, count, genregs); + kfree(genregs); } return ret; } -- 2.7.4
| |