Re: [patch] kprobes: dont steal interrupts from vm86

From: Stas Sergeev
Date: Thu Dec 09 2004 - 14:31:22 EST


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;
}