From: Roland McGrath Date: Mon, 16 Jul 2007 08:03:16 +0000 (-0700) Subject: Handle bogus %cs selector in single-step instruction decoding X-Git-Tag: v2.6.23-rc1~492 X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=29eb51101c02df517ca64ec472d7501127ad1da8 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 Signed-off-by: Linus Torvalds --- Adjusted to apply to Debian's 2.6.18 by dann frazier diff -urpN linux-source-2.6.18.orig/arch/i386/kernel/ptrace.c linux-source-2.6.18/arch/i386/kernel/ptrace.c --- linux-source-2.6.18.orig/arch/i386/kernel/ptrace.c 2006-09-19 21:42:06.000000000 -0600 +++ linux-source-2.6.18/arch/i386/kernel/ptrace.c 2007-09-19 23:45:45.949576125 -0600 @@ -172,14 +172,22 @@ static unsigned long convert_eip_to_line u32 *desc; unsigned long base; - down(&child->mm->context.sem); - desc = child->mm->context.ldt + (seg & ~7); - base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000); + seg &= ~7UL; - /* 16-bit code segment? */ - if (!((desc[1] >> 22) & 1)) - addr &= 0xffff; - addr += base; + down(&child->mm->context.sem); + if (unlikely((seg >> 3) >= child->mm->context.size)) + addr = -1L; /* bogus selector, access would fault */ + else { + desc = child->mm->context.ldt + seg; + base = ((desc[0] >> 16) | + ((desc[1] & 0xff) << 16) | + (desc[1] & 0xff000000)); + + /* 16-bit code segment? */ + if (!((desc[1] >> 22) & 1)) + addr &= 0xffff; + addr += base; + } up(&child->mm->context.sem); } return addr; diff -urpN linux-source-2.6.18.orig/arch/x86_64/kernel/ptrace.c linux-source-2.6.18/arch/x86_64/kernel/ptrace.c --- linux-source-2.6.18.orig/arch/x86_64/kernel/ptrace.c 2006-09-19 21:42:06.000000000 -0600 +++ linux-source-2.6.18/arch/x86_64/kernel/ptrace.c 2007-09-19 23:45:45.953575027 -0600 @@ -103,16 +103,25 @@ unsigned long convert_rip_to_linear(stru u32 *desc; unsigned long base; - down(&child->mm->context.sem); - desc = child->mm->context.ldt + (seg & ~7); - base = (desc[0] >> 16) | ((desc[1] & 0xff) << 16) | (desc[1] & 0xff000000); + seg &= ~7UL; - /* 16-bit code segment? */ - if (!((desc[1] >> 22) & 1)) - addr &= 0xffff; - addr += base; + down(&child->mm->context.sem); + if (unlikely((seg >> 3) >= child->mm->context.size)) + addr = -1L; /* bogus selector, access would fault */ + else { + desc = child->mm->context.ldt + seg; + base = ((desc[0] >> 16) | + ((desc[1] & 0xff) << 16) | + (desc[1] & 0xff000000)); + + /* 16-bit code segment? */ + if (!((desc[1] >> 22) & 1)) + addr &= 0xffff; + addr += base; + } up(&child->mm->context.sem); } + return addr; }