Commit c63855d0 authored by Roland McGrath's avatar Roland McGrath Committed by Ingo Molnar

x86 ptrace: disallow null cs/ss

In my revamp of the x86 ptrace code for setting register values,
I accidentally omitted a check that was there in the old code.
Allowing %cs to be 0 causes a bad crash in recovery from iret failure.
This patch fixes that regression against 2.6.24, and adds a comment
that should help prevent this subtlety from being overlooked again.
Signed-off-by: default avatarRoland McGrath <roland@redhat.com>
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent c1f766b5
...@@ -103,9 +103,26 @@ static int set_segment_reg(struct task_struct *task, ...@@ -103,9 +103,26 @@ static int set_segment_reg(struct task_struct *task,
if (invalid_selector(value)) if (invalid_selector(value))
return -EIO; return -EIO;
if (offset != offsetof(struct user_regs_struct, gs)) /*
* For %cs and %ss we cannot permit a null selector.
* We can permit a bogus selector as long as it has USER_RPL.
* Null selectors are fine for other segment registers, but
* we will never get back to user mode with invalid %cs or %ss
* and will take the trap in iret instead. Much code relies
* on user_mode() to distinguish a user trap frame (which can
* safely use invalid selectors) from a kernel trap frame.
*/
switch (offset) {
case offsetof(struct user_regs_struct, cs):
case offsetof(struct user_regs_struct, ss):
if (unlikely(value == 0))
return -EIO;
default:
*pt_regs_access(task_pt_regs(task), offset) = value; *pt_regs_access(task_pt_regs(task), offset) = value;
else { break;
case offsetof(struct user_regs_struct, gs):
task->thread.gs = value; task->thread.gs = value;
if (task == current) if (task == current)
/* /*
...@@ -227,12 +244,16 @@ static int set_segment_reg(struct task_struct *task, ...@@ -227,12 +244,16 @@ static int set_segment_reg(struct task_struct *task,
* Can't actually change these in 64-bit mode. * Can't actually change these in 64-bit mode.
*/ */
case offsetof(struct user_regs_struct,cs): case offsetof(struct user_regs_struct,cs):
if (unlikely(value == 0))
return -EIO;
#ifdef CONFIG_IA32_EMULATION #ifdef CONFIG_IA32_EMULATION
if (test_tsk_thread_flag(task, TIF_IA32)) if (test_tsk_thread_flag(task, TIF_IA32))
task_pt_regs(task)->cs = value; task_pt_regs(task)->cs = value;
#endif #endif
break; break;
case offsetof(struct user_regs_struct,ss): case offsetof(struct user_regs_struct,ss):
if (unlikely(value == 0))
return -EIO;
#ifdef CONFIG_IA32_EMULATION #ifdef CONFIG_IA32_EMULATION
if (test_tsk_thread_flag(task, TIF_IA32)) if (test_tsk_thread_flag(task, TIF_IA32))
task_pt_regs(task)->ss = value; task_pt_regs(task)->ss = value;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment