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*).
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?
(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.