aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
diff options
context:
space:
mode:
authorRoland McGrath <roland@redhat.com>2007-07-16 04:03:16 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-18 15:09:01 -0400
commit29eb51101c02df517ca64ec472d7501127ad1da8 (patch)
tree41101a87d0f895414f7e1a7c8676e54d1abedeea /arch/x86_64
parenta267c0a887064720dfab5775a4f09b20b4f8ec37 (diff)
Handle bogus %cs selector in single-step instruction decoding
The code for LDT segment selectors was not robust in the face of a bogus selector set in %cs via ptrace before the single-step was done. Signed-off-by: Roland McGrath <roland@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/kernel/ptrace.c23
1 files changed, 16 insertions, 7 deletions
diff --git a/arch/x86_64/kernel/ptrace.c b/arch/x86_64/kernel/ptrace.c
index fa6775ef729f..e83cc67155ac 100644
--- a/arch/x86_64/kernel/ptrace.c
+++ b/arch/x86_64/kernel/ptrace.c
@@ -102,16 +102,25 @@ unsigned long convert_rip_to_linear(struct task_struct *child, struct pt_regs *r
102 u32 *desc; 102 u32 *desc;
103 unsigned long base; 103 unsigned long base;
104 104
105 down(&child->mm->context.sem); 105 seg &= ~7UL;
106 desc = child->mm->context.ldt + (seg & ~7);
107 base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000);
108 106
109 /* 16-bit code segment? */ 107 down(&child->mm->context.sem);
110 if (!((desc[1] >> 22) & 1)) 108 if (unlikely((seg >> 3) >= child->mm->context.size))
111 addr &= 0xffff; 109 addr = -1L; /* bogus selector, access would fault */
112 addr += base; 110 else {
111 desc = child->mm->context.ldt + seg;
112 base = ((desc[0] >> 16) |
113 ((desc[1] & 0xff) << 16) |
114 (desc[1] & 0xff000000));
115
116 /* 16-bit code segment? */
117 if (!((desc[1] >> 22) & 1))
118 addr &= 0xffff;
119 addr += base;
120 }
113 up(&child->mm->context.sem); 121 up(&child->mm->context.sem);
114 } 122 }
123
115 return addr; 124 return addr;
116} 125}
117 126