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: