2004-09-07 23:54:34

by Zachary Amsden

[permalink] [raw]
Subject: PROBLEM: x86 alignment check bug

#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <setjmp.h>
#include <sys/mman.h>

void *faultAddress = 0;
jmp_buf env;


void getFaultAddress(int signo, struct siginfo *info, void *data)
{
faultAddress = info->si_addr;
longjmp(env, 1);
}

int main()
{
long *l;
struct sigaction sa;
sa.sa_sigaction = getFaultAddress;
sa.sa_flags = SA_SIGINFO | SA_ONESHOT;
l = (long *)mmap(0,4096, PROT_READ, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
printf("Read only write address = %08x\n", l);
sigaction(SIGSEGV, &sa, NULL);
if (!setjmp(env))
l[0] = 1;
else
printf("fault address = %08x\n", faultAddress);
l = (long *)mmap(0,8192, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
l[0] = 2;
l[1024] = 3;
l = (long *)(((char *)l)+1);
printf("Unaligned write address = %08x\n", l);
sigaction(SIGBUS, &sa, NULL);
__asm__ __volatile__("pushfl\n\t"
"orl $0x40000,(%esp)\n\t"
"popfl");
if (!setjmp(env))
l[0] = 4;
else
printf("fault address = %08x\n", faultAddress);
}


Attachments:
foo.c (0.99 kB)

2004-09-08 00:11:31

by David Miller

[permalink] [raw]
Subject: Re: PROBLEM: x86 alignment check bug

On Tue, 07 Sep 2004 16:51:41 -0700
Zachary Amsden <[email protected]> wrote:

> Clearly, this is not correct. Considering how difficult the fix is (the
> kernel must disassemble the faulting instruction and use register
> information to determine the faulting address),

While it is more difficult to disassemble x86 opcodes,
what you describe is exactly how we handle this on
sparc64. In fact we do opcode decoding for most fault
types.

2004-09-08 12:18:40

by Gabriel Paubert

[permalink] [raw]
Subject: Re: PROBLEM: x86 alignment check bug

On Tue, Sep 07, 2004 at 05:08:07PM -0700, David S. Miller wrote:
> On Tue, 07 Sep 2004 16:51:41 -0700
> Zachary Amsden <[email protected]> wrote:
>
> > Clearly, this is not correct. Considering how difficult the fix is (the
> > kernel must disassemble the faulting instruction and use register
> > information to determine the faulting address),
>
> While it is more difficult to disassemble x86 opcodes,
> what you describe is exactly how we handle this on
> sparc64. In fact we do opcode decoding for most fault
> types.

For page faults, cr2 gives you the linear address, i.e., after
adding the base of the segment, which you can only find
by looking up the GDT and/or LDT for the correct segment.

Of course, the address decoding depends also of the size
attributes of the code segment (16 or 32 bits for i386,
64 bits for x86_64) which needs also a lookup of CS in the
segment tables, and of a possible address prefix which
affects the decoding. Of course this is fraught with race
if another thread modifies the LDT at the same time.

Then most instructions use a standard memory address
encoding, but there are a few exceptions which implicitly
use ESI and/or EDI. For the ones that use two memory
addresses (movs/cmps), you'd have to even compute both
addresses and decide which one is the unaligned one.

I somehow suspect that Sparc is somewhat simpler to decode
than i386/x86_64 ;-)

Don't bloat the kernel with decoding this mess, please.
A helper library in user space, why not?

Regards,
Gabriel

2004-09-08 14:29:58

by Alan

[permalink] [raw]
Subject: Re: PROBLEM: x86 alignment check bug

On Mer, 2004-09-08 at 00:51, Zachary Amsden wrote:
> Exception reporting for alignment check violations on x86 is broken
> (unfortunately, rather badly, and rather hard to fix). Look at the trap
> function which fills in the si_addr field during an unaligned memory
> access, 2.6.8.1-mm4+, arch/i386/kernel/traps.c, Line 522:

So it fills in a value with random data that should be zero. Ok thats
hardly "badly".

> Clearly, this is not correct. Considering how difficult the fix is (the
> kernel must disassemble the faulting instruction and use register
> information to determine the faulting address)

It would be a nice extension although it would break other OS's if it
used %cr2 for this since they use it for thread id.


2004-09-08 18:30:16

by David Miller

[permalink] [raw]
Subject: Re: PROBLEM: x86 alignment check bug

On Wed, 8 Sep 2004 14:12:36 +0200
Gabriel Paubert <[email protected]> wrote:

> On Tue, Sep 07, 2004 at 05:08:07PM -0700, David S. Miller wrote:

I said:

> > While it is more difficult to disassemble x86 opcodes,

Then you said:

> I somehow suspect that Sparc is somewhat simpler to decode
> than i386/x86_64 ;-)

Thanks for agreeing with me! :-)

2004-09-09 16:29:19

by Petr Vandrovec

[permalink] [raw]
Subject: Re: PROBLEM: x86 alignment check bug

On 8 Sep 04 at 14:26, Alan Cox wrote:
> On Mer, 2004-09-08 at 00:51, Zachary Amsden wrote:
> > Exception reporting for alignment check violations on x86 is broken
> > (unfortunately, rather badly, and rather hard to fix). Look at the trap
> > function which fills in the si_addr field during an unaligned memory
> > access, 2.6.8.1-mm4+, arch/i386/kernel/traps.c, Line 522:
>
> So it fills in a value with random data that should be zero. Ok thats
> hardly "badly".

These are not random data. It is old value of CR2, which happens to
be address of last page fault which occured on this CPU.

By artifically triggering alignment fault you can find at which virtual
address last pagefault on this CPU occured - so you can have some
additional information channel which can disclose information about
other processes running on your box. And although probably all security
related apps learned that page faults can be sensed from time taken to
answer request, and add random delays to their failure answers, this
additional channel could be used to more precisely determine where
failure occured.

Yes, likelihood that you can use it to hack passwords on your linux box
is zero, but given that currently si_addr reports garbage for alignment
faults (on all x86 processors), why not always report zero (or all F,
or any other constant value or eip) in si_addr? It has same relevance as
any other random value, and when compared with semi-random value it does
not provide an additional information about system behavior.
Best regards,
Petr Vandrovec