[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] Trying to reproduce %eip corruption



Hi,
  I was trying to reproduce the error of %eip corruption and I manage to
get a small test program (from my previous one).

----------
/*
 * This program try to cause an exception raising a Xen failsafe callback
 * The idea is:
 * - one thread execute an infinite loop with some int3 instructions before
 *   and a CS segment allocated in LDT while handling a timer signal
 * - another thread just make sure that first is in the infinite loop and
 *   set CS to cause an exception on the first one
 * The first thread does not core just after the LDT change cause CS is cached
 * to it crash when kernel try to return to it.
 * Actually the first one running in the infinite loop can be stopped only by
 * an hardware interrupt so you have a Xen callback which try to return and
 * get an exception while doing IRET
 */
#undef NDEBUG
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <sys/mman.h>
#include <asm/ldt.h>
#include <pthread.h>

#define LDT_READ  0
#define LDT_WRITE 1

static void handler(int sig)
{
        static unsigned count = 0;
        if (++count == 60 * 1000)
                exit(0);
}

static void segv_handler(int sig)
{
        exit(0);
}

static int cs_ldt = -1;
static void
change_cs(void)
{
        struct user_desc desc;

        /* fills desc which represents the code segment */
        desc.entry_number = 0;
        desc.base_addr = 0;
        desc.limit = 0xffffffffu >> 12;
        desc.seg_32bit = 0x1;
        desc.contents = 0x2;
        desc.read_exec_only = 0x1;
        desc.limit_in_pages = 0x1;
        desc.seg_not_present = 0x0;
        desc.useable = 0x1;

        /* Writes a user_desc struct to the ldt */
        int err = syscall(SYS_modify_ldt, LDT_WRITE,
                          &desc, sizeof(desc));
        assert(!err);

        /* set cs to our selector to be able to make it core */
        asm(
"       pushl %eax\n"
"       movl $0x7, %eax\n" /* 0111: 0-Index 1-Using the LDT table 11-RPL of 3 */
"       pushl %eax\n"
"       pushl $1f\n"
"       retf\n"
"1:\n"
"       popl %eax\n"
        );

        cs_ldt = (desc.entry_number << 3) | 7;
}

static void *
corrupt_cs(void *arg)
{
        /* this assure that we set the selector while in the loop */
        sleep(2);
        assert(cs_ldt >= 0);

        struct user_desc desc;

        /* fills desc which represents the code segment */
        desc.entry_number = cs_ldt >> 3;
        desc.base_addr = 0;
        desc.limit = 1;
        desc.seg_32bit = 0x1;
        desc.contents = 0x2;
        desc.read_exec_only = 0x1;
        desc.limit_in_pages = 0x1;
        desc.seg_not_present = 0x1;
        desc.useable = 0x1;

        /* Writes a user_desc struct to the ldt */
        int err = syscall(SYS_modify_ldt, LDT_WRITE,
                          &desc, sizeof(desc));
        assert(!err);

        return NULL;
}

static void
faulty(void)
{
#if !defined(__x86_64__) && !defined(__i386__)
# error This code work only on Intel architecture!
#endif

        // wait for a core !!
        asm(
#ifdef __x86_64__
"       mov     $-513, %rax\n"
#else
"       mov     $-513, %eax\n"
#endif
"       jmp     1f\n"
"       int     $3\n"
"       int     $3\n"
"       int     $3\n"
"       int     $3\n"
"1:\n"
"       jmp     1b\n"
        );
}

int main(void)
{
        struct sigaction act;

        // set signal
        sigfillset(&act.sa_mask);
        act.sa_flags = 0;
        act.sa_handler = handler;

        int err = sigaction(SIGALRM, &act, NULL);
        assert(!err);

        act.sa_handler = segv_handler;
        err = sigaction(SIGSEGV, &act, NULL);
        assert(!err);

        // set timer
        struct itimerval ival = { { 0, 1000 }, { 0, 1000 } };
        err = setitimer(ITIMER_REAL, &ival, NULL);
        assert(!err);

        pthread_t thread_id;
        err = pthread_create(&thread_id, NULL, corrupt_cs, NULL);
        assert(!err);

        /* for some reasons pthread_create restre original cs */
        change_cs();

        /* faulting with SEGV is ok! */
        faulty();

        return 0;
}
----------

I run the program with this shell script

----------
#!/bin/bash

set -e
cd /
test -x xencore32
while true; do
        echo running test
        set +e
        su nobody -s /xencore32 && echo ok
        set -e
done
----------

The problems are now two:
- when program crash "normally" is cause an invalid instruction to be
executed while it should raise a SEGV
- sometimes it crashes very badly with an exception on the kernel and
after a couple of time you can be lucky and have your dom0 quite
useless.

When it crashes very badly I got this on screen (I couldn't use dmesg)

[ 242.372564] Process xencore32 (pid: 6645, ti=e797e000 task=e98957f0
task.ti=e797e000)
[ 242.372615] Stack:
[ 242.372665] Call Trace:
[ 242.372691]  <IRQ> 
[ 242.373864] Process xencore32 (pid: 6645, ti=e797e000 task=e98957f0
task.ti=e797e000)
[ 242.373916] Stack:
[ 242.374243] Call Trace:
[ 242.374803] Code: 8b 4d 10 85 c9 74 13 3b 5d 10 73 32 8b 45 10 2d 00
20 00 00 39 c3 73 13 eb 24 3b 5d f0 76 1f 8b 45 f0 05 fc 1f 00 00 39 c3
[  242.375302] EIP: [<c1013c04>] print_context_stack+0x94/0xc0 SS:ESP
0069:e797fe00

Anybody has some hint on how to resolve this problem?

Regards
  Frediano

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.