diff options
| -rw-r--r-- | arch/x86/kernel/ptrace.c | 25 |
1 files changed, 23 insertions, 2 deletions
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c index 96286df1bb81..702c33efea84 100644 --- a/arch/x86/kernel/ptrace.c +++ b/arch/x86/kernel/ptrace.c | |||
| @@ -103,9 +103,26 @@ static int set_segment_reg(struct task_struct *task, | |||
| 103 | if (invalid_selector(value)) | 103 | if (invalid_selector(value)) |
| 104 | return -EIO; | 104 | return -EIO; |
| 105 | 105 | ||
| 106 | if (offset != offsetof(struct user_regs_struct, gs)) | 106 | /* |
| 107 | * For %cs and %ss we cannot permit a null selector. | ||
| 108 | * We can permit a bogus selector as long as it has USER_RPL. | ||
| 109 | * Null selectors are fine for other segment registers, but | ||
| 110 | * we will never get back to user mode with invalid %cs or %ss | ||
| 111 | * and will take the trap in iret instead. Much code relies | ||
| 112 | * on user_mode() to distinguish a user trap frame (which can | ||
| 113 | * safely use invalid selectors) from a kernel trap frame. | ||
| 114 | */ | ||
| 115 | switch (offset) { | ||
| 116 | case offsetof(struct user_regs_struct, cs): | ||
| 117 | case offsetof(struct user_regs_struct, ss): | ||
| 118 | if (unlikely(value == 0)) | ||
| 119 | return -EIO; | ||
| 120 | |||
| 121 | default: | ||
| 107 | *pt_regs_access(task_pt_regs(task), offset) = value; | 122 | *pt_regs_access(task_pt_regs(task), offset) = value; |
| 108 | else { | 123 | break; |
| 124 | |||
| 125 | case offsetof(struct user_regs_struct, gs): | ||
| 109 | task->thread.gs = value; | 126 | task->thread.gs = value; |
| 110 | if (task == current) | 127 | if (task == current) |
| 111 | /* | 128 | /* |
| @@ -227,12 +244,16 @@ static int set_segment_reg(struct task_struct *task, | |||
| 227 | * Can't actually change these in 64-bit mode. | 244 | * Can't actually change these in 64-bit mode. |
| 228 | */ | 245 | */ |
| 229 | case offsetof(struct user_regs_struct,cs): | 246 | case offsetof(struct user_regs_struct,cs): |
| 247 | if (unlikely(value == 0)) | ||
| 248 | return -EIO; | ||
| 230 | #ifdef CONFIG_IA32_EMULATION | 249 | #ifdef CONFIG_IA32_EMULATION |
| 231 | if (test_tsk_thread_flag(task, TIF_IA32)) | 250 | if (test_tsk_thread_flag(task, TIF_IA32)) |
| 232 | task_pt_regs(task)->cs = value; | 251 | task_pt_regs(task)->cs = value; |
| 233 | #endif | 252 | #endif |
| 234 | break; | 253 | break; |
| 235 | case offsetof(struct user_regs_struct,ss): | 254 | case offsetof(struct user_regs_struct,ss): |
| 255 | if (unlikely(value == 0)) | ||
| 256 | return -EIO; | ||
| 236 | #ifdef CONFIG_IA32_EMULATION | 257 | #ifdef CONFIG_IA32_EMULATION |
| 237 | if (test_tsk_thread_flag(task, TIF_IA32)) | 258 | if (test_tsk_thread_flag(task, TIF_IA32)) |
| 238 | task_pt_regs(task)->ss = value; | 259 | task_pt_regs(task)->ss = value; |
