Commit 0998e4228aca046fbd747c3fed909791d52e88eb
Committed by
Linus Torvalds
1 parent
f2ab446124
Exists in
master
and in
4 other branches
[PATCH] x86: privilege cleanup
Privilege checking cleanup. Originally, these diffs were much greater, but recent cleanups in Linux have already done much of the cleanup. I added some explanatory comments in places where the reasoning behind certain tests is rather subtle. Also, in traps.c, we can skip the user_mode check in handle_BUG(). The reason is, there are only two call chains - one via die_if_kernel() and one via do_page_fault(), both entering from die(). Both of these paths already ensure that a kernel mode failure has happened. Also, the original check here, if (user_mode(regs)) was insufficient anyways, since it would not rule out BUG faults from V8086 mode execution. Saving the %ss segment in show_regs() rather than assuming a fixed value also gives better information about the current kernel state in the register dump. Signed-off-by: Zachary Amsden <zach@vmware.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 3 changed files with 11 additions and 5 deletions Side-by-side Diff
arch/i386/kernel/signal.c
| ... | ... | @@ -604,7 +604,9 @@ |
| 604 | 604 | * We want the common case to go fast, which |
| 605 | 605 | * is why we may in certain cases get here from |
| 606 | 606 | * kernel mode. Just return without doing anything |
| 607 | - * if so. | |
| 607 | + * if so. vm86 regs switched out by assembly code | |
| 608 | + * before reaching here, so testing against kernel | |
| 609 | + * CS suffices. | |
| 608 | 610 | */ |
| 609 | 611 | if (!user_mode(regs)) |
| 610 | 612 | return 1; |
arch/i386/kernel/traps.c
| ... | ... | @@ -210,7 +210,7 @@ |
| 210 | 210 | unsigned short ss; |
| 211 | 211 | |
| 212 | 212 | esp = (unsigned long) (®s->esp); |
| 213 | - ss = __KERNEL_DS; | |
| 213 | + savesegment(ss, ss); | |
| 214 | 214 | if (user_mode(regs)) { |
| 215 | 215 | in_kernel = 0; |
| 216 | 216 | esp = regs->esp; |
| ... | ... | @@ -266,9 +266,6 @@ |
| 266 | 266 | char *file; |
| 267 | 267 | char c; |
| 268 | 268 | unsigned long eip; |
| 269 | - | |
| 270 | - if (user_mode(regs)) | |
| 271 | - goto no_bug; /* Not in kernel */ | |
| 272 | 269 | |
| 273 | 270 | eip = regs->eip; |
| 274 | 271 |
include/asm-i386/ptrace.h
| ... | ... | @@ -61,6 +61,13 @@ |
| 61 | 61 | struct task_struct; |
| 62 | 62 | extern void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs, int error_code); |
| 63 | 63 | |
| 64 | +/* | |
| 65 | + * user_mode_vm(regs) determines whether a register set came from user mode. | |
| 66 | + * This is true if V8086 mode was enabled OR if the register set was from | |
| 67 | + * protected mode with RPL-3 CS value. This tricky test checks that with | |
| 68 | + * one comparison. Many places in the kernel can bypass this full check | |
| 69 | + * if they have already ruled out V8086 mode, so user_mode(regs) can be used. | |
| 70 | + */ | |
| 64 | 71 | static inline int user_mode(struct pt_regs *regs) |
| 65 | 72 | { |
| 66 | 73 | return (regs->xcs & 3) != 0; |