From dillon@backplane.com  Mon Jul 27 21:53:49 1998
Received: from apollo.backplane.com (apollo.backplane.com [209.157.86.2])
          by hub.freebsd.org (8.8.8/8.8.8) with ESMTP id VAA01485
          for <FreeBSD-gnats-submit@freebsd.org>; Mon, 27 Jul 1998 21:53:48 -0700 (PDT)
          (envelope-from dillon@backplane.com)
Received: (dillon@localhost) by apollo.backplane.com (8.8.8/8.6.5) id VAA18002; Mon, 27 Jul 1998 21:53:18 -0700 (PDT)
Message-Id: <199807280453.VAA18002@apollo.backplane.com>
Date: Mon, 27 Jul 1998 21:53:18 -0700 (PDT)
From: Matthew Dillon <dillon@backplane.com>
Reply-To: dillon@backplane.com
To: FreeBSD-gnats-submit@freebsd.org
Subject: VM system fails to remove mapped page on truncate in some situations
X-Send-Pr-Version: 3.2

>Number:         7422
>Category:       kern
>Synopsis:       FreeBSD-current VM systems do not properly remove mapped pages on truncate in some situations.  -stable does.
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jul 27 22:00:02 PDT 1998
>Closed-Date:    Tue Aug 25 06:48:11 PDT 1998
>Last-Modified:  Tue Aug 25 06:49:35 PDT 1998
>Originator:     Matthew Dillon
>Release:        FreeBSD 3.0-CURRENT i386
>Organization:
Best Internet Communications, Inc.
>Environment:

	Generic FreeBSD-current machine (CVS as of 26 Jul 98)
	Generic FreeBSD-stable machine (CVS somewhere between 2.2.6 and 2.2.7)

>Description:

	ON a -current machine:

	If you open a file and use write() to write to it and either
	you or another process mmap()'s the file, if the file is then
	truncated mmap()'d pages that should have been removed (made
	illegal) are sometimes not and can still be referenced with
	the original data still intact.

	Example:  create a file, write 4096+(512 to 4095) bytes to it.
	mmap the file, reference the second page of the mmap 
	(volatile x = ptr[4096];), then ftruncate the file to 4096
	bytes.  You can still reference the second page of the mmap
	(which should now be illegal) and it still contains the 
	original data written to it.  

	Now repeat the process but write 4096+4096 bytes to the
	file.  now when you ftruncate, referencing ptr[4096]
	after the ftruncate call will correctly segfault.

	(NOTE:  This is different from the file corruption bug
	previously reported.  This bug does not corrupt the file
	but does 'corrupt' the mmap.  It may or may not be
	related to the previously reported file corruption-on-
	mmap while appending bug).

	(NOTE:  The program properly segfaults in both cases on
	a -stable machine).

>How-To-Repeat:


/*
 * BADVM.C
 */

#include <sys/types.h>
#include <sys/fcntl.h>
#include <sys/types.h>
#include <sys/mman.h>
#include <stdio.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdarg.h>

int
main(int ac, char **av)
{
    int fd;
    char buf[4096 + 4096];
    volatile char *base;
    volatile int x;
    int n;

    if (ac == 1) {
	printf("Run with an argument of '512' and then run with an argument of '4096'\n");
	exit(1);
    }
    n = strtol(av[1], NULL, 0);
    if (n < 0 || n > 4096) {
	printf("argument out of bounds\n");
	exit(1);
    }

    remove("test");
    if ((fd = open("test", O_RDWR|O_CREAT, 0644)) < 0)
	perror("open");
    memset(buf, 1, sizeof(buf));
    if (write(fd, buf, 4096 + n) != 4096 + n)
	perror("write");
    base = mmap((caddr_t)0, 8192, PROT_READ, MAP_SHARED, fd, 0);
    printf("map: %08lx\n", (long)base);
    printf("base[4096] should be 1: %d\n", base[4096]);
    ftruncate(fd, 4096);
    printf("base[4096] should fault: ");
    fflush(stdout);
    printf("%d\n", base[4096]);
    puts("oops, it didn't");
    lseek(fd, 4096, 0);
    memset(buf, 2, sizeof(buf));
    if (write(fd, buf, 4096) != 4096)
	perror("write");
    printf("base[4096] should be 2: %d\n", base[4096]);
    return(0);
}

>Fix:
	

>Release-Note:
>Audit-Trail:

From: Luoqi Chen <luoqi@chen.ml.org>
To: freebsd-gnats-submit@freebsd.org, dillon@backplane.com
Cc: luoqi@watermarkgroup.com
Subject: Re: kern/7422: FreeBSD-current VM systems do not properly remove mapped 
 pages on truncate in some situations.  -stable does.
Date: Thu, 13 Aug 1998 20:35:13 -0400

 This is a one-line bug in vnode_pager_setsize() function. Below is
 the fix, note that the higher end of page index range in function
 vm_object_page_remove() is not inclusive (I got rid of some auto
 variables and unused calculation, so the fix is more than one line).
 This bug should exist in -stable also, not sure why it behaved
 correctly (I don't have a -stable machine to test with).
 
 -lq
 
 Index: sys/vm/vnode_pager.c
 ===================================================================
 RCS file: /fun/cvs/src/sys/vm/vnode_pager.c,v
 retrieving revision 1.94
 diff -u -r1.94 vnode_pager.c
 --- vnode_pager.c       1998/07/11 11:30:46     1.94
 +++ vnode_pager.c       1998/08/14 00:23:36
 @@ -271,12 +271,9 @@
                 vm_ooffset_t nsizerounded;
                 nsizerounded = IDX_TO_OFF(OFF_TO_IDX(nsize +
 PAGE_MASK));
                 if (nsizerounded < object->un_pager.vnp.vnp_size) {
 -                       vm_pindex_t st, end;
 -                       st = OFF_TO_IDX(nsize + PAGE_MASK);
 -                       end = OFF_TO_IDX(object->un_pager.vnp.vnp_size);
 -
                         vm_freeze_copyopts(object, OFF_TO_IDX(nsize),
 object->size);
 -                       vm_object_page_remove(object, st, end, FALSE);
 +                       vm_object_page_remove(object, OFF_TO_IDX(nsize +
 PAGE_MASK),
 +                               object->size, FALSE);
                 }
                 /*
                  * this gets rid of garbage at the end of a page that is
 now

From: Matthew Dillon <dillon@backplane.com>
To: Luoqi Chen <luoqi@chen.ml.org>
Cc: freebsd-gnats-submit@freebsd.org, luoqi@watermarkgroup.com
Subject: Re: kern/7422: FreeBSD-current VM systems do not properly remove mapped 
Date: Thu, 13 Aug 1998 17:48:38 -0700 (PDT)

     Great!  That's one down!  I was hoping someone would be able to fix
     that one quickly and, indeed, so it happens!
 
     I'll run the patch on our -current test box (running a news system) to 
     life-test it.
 
     The mmap-reading/file-writing corruption is going to be a much stickier 
     problem to solve.  I think the key item is that the only thing writing
     to the file is write(), and a shared+RO mmap() is capable of causing the
     written file data to become corrupted as of the time of the write or 
     as of a slightly later time.  I've been concentrating on the page fault
     code trying to figure out how it could corrupt the buffer cache, but
     it's virtual black magic to me.
 
 						-Matt
 
     Matthew Dillon  Engineering, HiWay Technologies, Inc. & BEST Internet 
                     Communications
     <dillon@backplane.com> (Please include original email in any response)    
 
 :This is a one-line bug in vnode_pager_setsize() function. Below is
 :the fix, note that the higher end of page index range in function
 :vm_object_page_remove() is not inclusive (I got rid of some auto
 :variables and unused calculation, so the fix is more than one line).
 :This bug should exist in -stable also, not sure why it behaved
 :correctly (I don't have a -stable machine to test with).
 :
 :-lq
 :
 :Index: sys/vm/vnode_pager.c
 :===================================================================
 :RCS file: /fun/cvs/src/sys/vm/vnode_pager.c,v
 :retrieving revision 1.94
 :diff -u -r1.94 vnode_pager.c
 :...
 
 
State-Changed-From-To: open->closed 
State-Changed-By: luoqi 
State-Changed-When: Tue Aug 25 06:48:11 PDT 1998 
State-Changed-Why:  
patch committed 
>Unformatted:
