Subject: kern/5834: shmdt(2) deallocates wrong region of pages with UVM.
To: None <gnats-bugs@gnats.netbsd.org>
From: None <yasufu-i@is.aist-nara.ac.jp>
List: netbsd-bugs
Date: 07/25/1998 05:24:38
>Number:         5834
>Category:       kern
>Synopsis:       shmdt(2) deallocates wrong region of pages with UVM.
>Confidential:   no
>Severity:       serious
>Priority:       high
>Responsible:    kern-bug-people (Kernel Bug People)
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Fri Jul 24 13:35:01 1998
>Last-Modified:
>Originator:     ITOH Yasufumi
>Organization:
	Nara Institute of Science and Technology, Nara, Japan
>Release:        1.3F (July 24, 1998)
>Environment:
System: NetBSD libble.my.domain 1.3F NetBSD 1.3F (LIBBLE) #1: Sat Jul 25 03:56:40 JST 1998 itohy@libble.my.domain:/usr/src/sys/arch/alpha/compile/LIBBLE alpha


>Description:
	shmdt(2) frees unexpected mapping with the UVM kernel option.
	The starting address is correct, but the size is wong,
	and the succeeding pages are also unmapped.

	I noticed this on Alpha, since it deallocates vast space
	including the stack segment(!) and the process receives
	SIGSEGV at the next stack operation.

>How-To-Repeat:
	Try this on NetBSD/alpha with UVM & SYSVSHM option.
	The program gets SIGSEGV after shmdt(),
	since the stack does not exist any longer.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>

int
main()
{
	int id;
	void *addr;
	int status = 1;
	void *volatile foo;	/* forced on stack */

	if ((id = shmget(IPC_PRIVATE, 16384, IPC_CREAT|0600)) == -1) {
		perror("shmget");
		return 1;
	}
	addr = shmat(id, 0, 0);
	if (addr == (void *) -1) {
		perror("shmat");
		goto out;
	}

	foo = &foo;	/* try write stack */
	printf("id: %d, addr: %p, foo: %p\n", id, addr, foo);

	if (shmdt(addr)) {
		perror("shmdt");
		goto out;
	}

	foo = NULL;	/* touch stack -- SEGV here */

	status = 0;	/* all success */

out:	if (shmctl(id, IPC_RMID, NULL))
		perror("shmctl(IPC_RMID)");

	return status;
}

>Fix:
	Apply this patch to sys/kern.

diff -uF^[a-zA-Z_][a-z 	A-Z0-9_]*(.*[^;]$ sys/kern/sysv_shm.c.orig sys/kern/sysv_shm.c
--- sys/kern/sysv_shm.c.orig	Fri May  8 20:20:45 1998
+++ sys/kern/sysv_shm.c	Sat Jul 25 03:56:13 1998
@@ -163,8 +163,7 @@ shm_delete_mapping(vm, shmmap_s)
 	shmseg = &shmsegs[segnum];
 	size = (shmseg->shm_segsz + CLOFSET) & ~CLOFSET;
 #ifdef UVM
-	result = uvm_deallocate(&vm->vm_map,
-				shmmap_s->va, shmmap_s->va + size);
+	result = uvm_deallocate(&vm->vm_map, shmmap_s->va, size);
 #else
 	result = vm_map_remove(&vm->vm_map,
 			       shmmap_s->va, shmmap_s->va + size);
>Audit-Trail:
>Unformatted: