All of lore.kernel.org
 help / color / mirror / Atom feed
* PROBLEM: x86 alignment check bug
@ 2004-09-07 23:51 Zachary Amsden
  2004-09-08  0:08 ` David S. Miller
  2004-09-08 13:26 ` Alan Cox
  0 siblings, 2 replies; 6+ messages in thread
From: Zachary Amsden @ 2004-09-07 23:51 UTC (permalink / raw)
  To: linux-kernel, davej, hpa, bgerst, Riley

[-- Attachment #1: Type: text/plain, Size: 1864 bytes --]

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:

DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, 
BUS_ADRALN, get_cr2())

The hardware does not fill in %cr2 with the faulting address on 
alignment check exceptions (at least on all processors I have tested); 
this assumed behavior is also not documented in either the Intel or AMD 
processor manuals, so at least in my understanding, it does not exist.  
What happens instead is that the last occuring page fault address is 
passed to the user via the siginfo struct.  This address may be 
completely random and have nothing at all to do with the alignment check 
exception.  If any memory debuggers use #AC and are relying on SIGBUS to 
provide a correct address, they may get very confused.

I've attached a sample C program demonstrating the problem.

zach-dev:zach $ ./a.out
Read only write address = 40016000
fault address = 40016000
Unaligned write address = 40018001
fault address = 400a2b70

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), perhaps it is best to 
simply remove the extra error info from the siginfo struct - the single 
UNIX spec does not actually say that SIGBUS must provide and address 
information.  If the si_addr info is left, it should be clearly 
documented that it does not work properly.

Keywords: signal,i386
Kernel version: apparently, all

Doing a historical search, apparently this was discovered before:
http://seclists.org/lists/linux-kernel/2001/May/0309.html

Zachary Amsden (zach@vmware.com)

[-- Attachment #2: foo.c --]
[-- Type: text/plain, Size: 1016 bytes --]

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

^ permalink raw reply	[flat|nested] 6+ messages in thread
* Re: PROBLEM: x86 alignment check bug
@ 2004-09-09 16:29 Petr Vandrovec
  0 siblings, 0 replies; 6+ messages in thread
From: Petr Vandrovec @ 2004-09-09 16:29 UTC (permalink / raw)
  To: Alan Cox; +Cc: Linux Kernel Mailing List, davej, hpa, bgerst, Riley, zach

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


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2004-09-09 16:29 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2004-09-07 23:51 PROBLEM: x86 alignment check bug Zachary Amsden
2004-09-08  0:08 ` David S. Miller
2004-09-08 12:12   ` Gabriel Paubert
2004-09-08 18:26     ` David S. Miller
2004-09-08 13:26 ` Alan Cox
  -- strict thread matches above, loose matches on Subject: below --
2004-09-09 16:29 Petr Vandrovec

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.