Messages in this thread | | | Date | Thu, 09 Dec 2004 22:28:25 +0300 | From | Stas Sergeev <> | Subject | Re: [patch] kprobes: dont steal interrupts from vm86 |
| |
Hi.
Prasanna S Panchamukhi wrote: > The patch below takes both the cases into > consideration. OK, perhaps this one is better, at least it no longer plays on gcc optimization, so that I can reproduce the Oopses again, for good and for test-case. But I think you really should consider checking regs->xcs instead of explicitly checking the corner cases like 0xcd,3.
> I am not able to think of a case, where > address is invalid when it enters int3 handler. > I would appreciate if you can provide such a > test case. I already did - it was my very first test-case which produced the Oops on the if(*addr!=...) dereference, but you worked around by checking the VM flag (well, it must be checked, but not after you already used "addr" a couple of times, IMHO). OK, but if you need another test-case, here it is. Much simpler than the vm86 one. It can work in 2 modes: started without args, it will print the diagnostic (passed or failed) and exit. If started with any arg, it will Oops the kernel. This happens both with your latest patch and without it. This doesn't happen with your previous patch (no Oops), but then fixing problems by exploiting the gcc optimization was not the best idea I think.
#include <stdio.h> #include <stdlib.h> #include <signal.h> #include <linux/unistd.h> #include <asm/ldt.h> #include <asm/segment.h> #include <asm/page.h> #include <sys/mman.h>
_syscall3(int, modify_ldt, int, func, void *, ptr, unsigned long, bytecount)
static int set_ldt_entry(int entry, unsigned long base, unsigned int limit, int seg_32bit_flag, int contents, int read_only_flag, int limit_in_pages_flag, int seg_not_present, int useable) { struct modify_ldt_ldt_s ldt_info; ldt_info.entry_number = entry; ldt_info.base_addr = base; ldt_info.limit = limit; ldt_info.seg_32bit = seg_32bit_flag; ldt_info.contents = contents; ldt_info.read_exec_only = read_only_flag; ldt_info.limit_in_pages = limit_in_pages_flag; ldt_info.seg_not_present = seg_not_present; ldt_info.useable = useable;
return modify_ldt(1, &ldt_info, sizeof(ldt_info)); }
void my_trap(int sig) { printf("Test passed, All OK!\n"); exit(0); }
int main(int argc, char *argv[]) { unsigned char *ptr; if (mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED) { perror("mmap"); return 1; } if ((ptr = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)) == MAP_FAILED) { perror("mmap"); return 1; } if (argc == 1) /* no-Oops mode */ *(unsigned char *)0 = 1; /* Set the no-Oops flag :) */ /* Create the LDT entry */ #define MY_CS (__USER_CS | 4) set_ldt_entry(MY_CS >> 3, (unsigned long)ptr, PAGE_SIZE - 1, 1, MODIFY_LDT_CONTENTS_CODE, 1, 0, 0, 0); ptr[0] = 0xcc; ptr[1] = 0xcb; signal(SIGTRAP, my_trap); asm volatile ("lcall %0,$0\n"::"i"(MY_CS)); printf("Stolen interrupt, very bad.\n"); return 0; }
| |