Subject: port-i386/2830: SIGBUS is inappropriate for VM protection violations
To: None <gnats-bugs@gnats.netbsd.org>
From: Mike Long <mike.long@analog.com>
List: netbsd-bugs
Date: 10/11/1996 04:10:10
>Number: 2830
>Category: port-i386
>Synopsis: SIGBUS is inappropriate for VM protection violations
>Confidential: no
>Severity: serious
>Priority: medium
>Responsible: gnats-admin (GNATS administrator)
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Fri Oct 11 01:20:01 1996
>Last-Modified:
>Originator: Mike Long <mike.long@analog.com>
>Organization:
You Rang?
>Release: 1.2
>Environment:
System: NetBSD azathoth 1.2 NetBSD 1.2 (AZATHOTH) #101: Fri Oct 11 02:32:55 EDT 1996 root@azathoth:/usr/src/sys/arch/i386/compile/AZATHOTH i386
>Description:
The i386 port raises SIGBUS when a process attempts to modify
a read-only page, instead of the more appropriate SIGSEGV. This
behavior makes SPICE core dump, because it tries to determine the data
segment size by probing memory <shudder>.
>How-To-Repeat:
Run the code below, which has been condensed from SPICE 3F4's
src/lib/fte/resource.c . Of course it's a portability nightmare, but
that's not the point.
#include <sys/types.h>
#include <signal.h>
#include <setjmp.h>
/*
* baseaddr( ) returns the base address of the data segment on most Unix
* systems. It's an ugly hack for info that should be provided by the OS.
*/
/* Does anyone use a pagesize < 256 bytes?? I'll bet not;
* too small doesn't hurt
*/
#define LOG2_PAGESIZE 8
static jmp_buf env;
static void
fault( )
{
signal(SIGSEGV, (void (*)()) fault); /* SysV style */
longjmp(env, 1);
}
static void *
baseaddr( )
{
char *low, *high, *at;
long x;
void (*orig_signal)( );
low = 0;
high = (char *) ((unsigned long) sbrk(0) & ~((1 << LOG2_PAGESIZE) - 1));
orig_signal = signal(SIGSEGV, (void (*)()) fault);
do {
at = (char *) ((((long)low >> LOG2_PAGESIZE)
+ ((long)high >> LOG2_PAGESIZE))
<< (LOG2_PAGESIZE - 1));
if (at == low || at == high) {
break;
}
if (setjmp(env)) {
low = at;
continue;
} else
x = *at;
if (setjmp(env)) {
low = at;
continue;
} else
*at = x;
high = at;
} while (1);
(void) signal(SIGSEGV, (void (*)()) orig_signal);
return (void *) high;
}
int
main( )
{
printf("testing\n");
printf("baseaddr: %#8x topaddr: %#8x\n", baseaddr( ), sbrk(0));
return 0;
}
>Fix:
Apply the patch below.
*** src/sys/arch/i386/i386/trap.c.orig Sun May 5 07:30:36 1996
--- src/sys/arch/i386/i386/trap.c Fri Oct 11 02:06:32 1996
***************
*** 421,429 ****
goto we_re_toast;
}
! trapsignal(p, (rv == KERN_PROTECTION_FAILURE
! #ifdef COMPAT_LINUX
! && p->p_emul != &emul_linux_aout && p->p_emul != &emul_linux_elf
! #endif
! ) ? SIGBUS : SIGSEGV, T_PAGEFLT);
break;
}
--- 421,425 ----
goto we_re_toast;
}
! trapsignal(p, SIGSEGV, T_PAGEFLT);
break;
}
>Audit-Trail:
>Unformatted: