Bug 437712 - ptrace: PTRACE_SETREGS does not set RIP
ptrace: PTRACE_SETREGS does not set RIP
Status: CLOSED NOTABUG
Product: Red Hat Enterprise Linux 4
Classification: Red Hat
Component: kernel (Show other bugs)
4.6
x86_64 Linux
medium Severity medium
: rc
: ---
Assigned To: Red Hat Kernel Manager
Martin Jenner
:
Depends On:
Blocks:
  Show dependency treegraph
 
Reported: 2008-03-16 18:13 EDT by Jan Kratochvil
Modified: 2008-03-17 10:09 EDT (History)
2 users (show)

See Also:
Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of:
Environment:
Last Closed: 2008-03-17 10:09:04 EDT
Type: ---
Regression: ---
Mount Type: ---
Documentation: ---
CRM:
Verified Versions:
Category: ---
oVirt Team: ---
RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: ---


Attachments (Terms of Use)

  None (edit)
Description Jan Kratochvil 2008-03-16 18:13:42 EDT
Description of problem:
PTRACE_SETREGS(rip=XYZ) followed by PTRACE_GETREGS returns the original RIP value.

Version-Release number of selected component (if applicable):
kernel-smp-2.6.9-68.10.EL.x86_64
(upstream 2.6.22-rc4-git7.x86_64 is OK)
(RHEL-5 kernel-2.6.18-53.1.13.el5.x86_64 is OK)

How reproducible:
Always.

Steps to Reproduce:
1. wget -O user-regs-peekpoke.c
'http://sources.redhat.com/cgi-bin/cvsweb.cgi/~checkout~/tests/ptrace-tests/tests/user-regs-peekpoke.c?cvsroot=systemtap'
2. gcc -o user-regs-peekpoke user-regs-peekpoke.c -Wall -ggdb2 -D_GNU_SOURCE
3. ./user-regs-peekpoke; echo $?

Actual results:
1

Expected results:
0

Additional info:
Register RIP remains unmodified.
wdiff:
$x = {r15 = 506097522914230528, r14 = 1084818905618843912, r13 =
1663540288323457296, r12 = 2242261671028070680,
  rbp = 2820983053732684064, rbx = 3399704436437297448, r11 =
3978425819141910832, r10 = 4557147201846524216,
  r9 = 5135868584551137600, r8 = 5714589967255750984, rax = 6293311349960364368,
rcx = 6872032732664977752,
  rdx = 7450754115369591136, rsi = 8029475498074204520, rdi =
8608196880778817904, orig_rax = 9186918263483431288,
  rip = [-9765639646188044672,-] {+248369046109,+} cs = 51, eflags = 514, rsp =
11501803794301884824, ss = 43, fs_base = 182894074624, gs_base = 0,
  ds = 0, es = 0, fs = 0, gs = 0}

It aborts at the source line 146 (of rev 1.2).

It breaks many other ptrace-testsuite testcases (step-jump-cont, erestart*).
Comment 3 Roland McGrath 2008-03-16 18:52:44 EDT
If I'm reading that wdiff fragment correctly, the old rip value was 0x39d3f2e25d
and you tried to set rip to 0x8786858483828180.  Is that correct?

User addresses on x86_64 cannot be above 0x7fffffffefff on recent kernels, or
above 0x7fbfffffff of RHEL4 kernels.

On most kernels, you can set any rip value you like via ptrace.  For any invalid
value (even the high ones that are permanently invalid), the thread will just
get the normal signal when it resumes at the bad rip.

On RHEL4, the fix for CAN-2005-1762 was kept conservative by making ptrace
disallow setting an rip value that is too high to ever be a valid user address
on that kernel.  On upstream kernels, the issue was fixed a different way that
was more invasive to deep kernel code, but did not affect the ptrace semantics
in this way.

If you try to set rip to the same value with PTRACE_POKEUSR, it will fail with
-EIO.  However, PTRACE_SETREGS just ignores all individual failures from setting
bad values (e.g. also nonzero segment register values with either of the low two
bits clear) and just sets what it can and returns success.

So AFAICT, the issue is trying to set bogus values for rip.  If the tests are
constrained to permissible values, they should work OK on all kernels.  Is that
a sufficient workaround?
Comment 4 Jan Kratochvil 2008-03-17 10:09:04 EDT
(In reply to comment #3)
> If I'm reading that wdiff fragment correctly, the old rip value was
> 0x39d3f2e25d and you tried to set rip to 0x8786858483828180.  Is that correct?

Yes.

> If you try to set rip to the same value with PTRACE_POKEUSR, it will fail with
> -EIO.  However, PTRACE_SETREGS just ignores all individual failures from
> setting bad values

Later I thought PTRACE_SETREGS should -EIO in such case but OK.

> So AFAICT, the issue is trying to set bogus values for rip.  If the tests are
> constrained to permissible values, they should work OK on all kernels.
> Is that a sufficient workaround?

Yes, implemented for `user-regs-peekpoke'.

Thanks for the explanation.

Note You need to log in before you can comment on or make changes to this bug.