From tim@robbins.dropbear.id.au  Sun Mar 17 22:33:10 2002
Return-Path: <tim@robbins.dropbear.id.au>
Received: from descent.robbins.dropbear.id.au (078.b.004.mel.iprimus.net.au [210.50.37.78])
	by hub.freebsd.org (Postfix) with ESMTP id 60A1C37B421
	for <FreeBSD-gnats-submit@freebsd.org>; Sun, 17 Mar 2002 22:32:38 -0800 (PST)
Received: (from tim@localhost)
	by descent.robbins.dropbear.id.au (8.11.6/8.11.6) id g2I6WCE00274;
	Mon, 18 Mar 2002 17:32:12 +1100 (EST)
	(envelope-from tim)
Message-Id: <200203180632.g2I6WCE00274@descent.robbins.dropbear.id.au>
Date: Mon, 18 Mar 2002 17:32:12 +1100 (EST)
From: "Tim J. Robbins" <tim@robbins.dropbear.id.au>
Reply-To: "Tim J. Robbins" <tim@robbins.dropbear.id.au>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: sendfile(2) on smbfs fails, exposes kernel memory to userspace
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         36038
>Category:       kern
>Synopsis:       [smbfs] sendfile(2) on smbfs fails, exposes kernel memory to userspace
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Mar 17 22:40:01 PST 2002
>Closed-Date:    Mon Sep 18 19:09:08 GMT 2006
>Last-Modified:  Mon Sep 18 19:09:08 GMT 2006
>Originator:     Tim J. Robbins
>Release:        FreeBSD 4.5-STABLE i386
>Organization:
>Environment:
System: FreeBSD descent.robbins.dropbear.id.au 4.5-STABLE FreeBSD 4.5-STABLE #7: Mon Mar 18 16:43:16 EST 2002 tim@descent.robbins.dropbear.id.au:/usr/obj/usr/src/sys/DESCENT i386


	
>Description:
sendfile(2) on a file on a smbfs mount usually fails with errno == EFAULT.
However, in certain situations it can accidentally leak what appears to
be random kernel memory.
>How-To-Repeat:
This simple program uses sendfile() to copy the specified files to
standard output (which must be a socket):

#include <sys/types.h>
#include <sys/socket.h>
#include <sys/uio.h>

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


int
main(int argc, char *argv[])
{
	const char *fn;
	int fd;

	while ((fn = *++argv) != NULL) {
		if ((fd = open(fn, O_RDONLY)) < 0)
			err(1, "open %s", fn);
		if (sendfile(fd, STDOUT_FILENO, 0, 0, NULL, NULL, 0) < 0)
			err(1, "sendfile %s", fn);
		close(fd);
	}

	return(0);
}


When run from inetd, it never gives the actual contents of the file like
it should (and does on other filesystems). It often gets EFAULT, other
times it dumps random garbage.

A more complicated program demonstrating this problem is thttpd (in ports),
which uses sendfile(2) to serve static pages. It does not work if the
pages it should serve are on smbfs.

>Fix:
Not known.
>Release-Note:
>Audit-Trail:

From: David Greenman <dg@root.com>
To: "Tim J. Robbins" <tim@robbins.dropbear.id.au>
Cc: FreeBSD-gnats-submit@FreeBSD.org
Subject: Re: kern/36038: sendfile(2) on smbfs fails, exposes kernel memory to userspace
Date: Sun, 17 Mar 2002 23:12:28 -0800

 >sendfile(2) on a file on a smbfs mount usually fails with errno == EFAULT.
 >However, in certain situations it can accidentally leak what appears to
 >be random kernel memory.
 
    After a quick look at this, it appears that md_get_uio() (located in
 kern/sysbr_mchain.c) doesn't support UIO_NOCOPY, which sendfile() requires.
 This function (and it's children) appear to be only used by smbfs.
 
 -DG
 
 David Greenman
 Co-founder, The FreeBSD Project - http://www.freebsd.org
 President, TeraSolutions, Inc. - http://www.terasolutions.com
 President, Download Technologies, Inc. - http://www.downloadtech.com
 Pave the road of life with opportunities.

From: "Tim J. Robbins" <tim@robbins.dropbear.id.au>
To: David Greenman <dg@root.com>
Cc: FreeBSD-gnats-submit@FreeBSD.org
Subject: Re: kern/36038: sendfile(2) on smbfs fails, exposes kernel memory to userspace
Date: Tue, 19 Mar 2002 09:16:28 +1100

 On Sun, Mar 17, 2002 at 11:12:28PM -0800, David Greenman wrote:
 
 >    After a quick look at this, it appears that md_get_uio() (located in
 > kern/sysbr_mchain.c) doesn't support UIO_NOCOPY, which sendfile() requires.
 > This function (and it's children) appear to be only used by smbfs.
 
 Thanks for helping to track down the bug so quickly.
 
 md_get_uio() made the incorrect assumption that anything other than
 UIO_SYSSPACE was UIO_USER(I)SPACE.
 
 I'm not sure how to implement UIO_NOCOPY for mchain, so these patches
 just make it return an error instead of trying to copy bogus data,
 leading to EFAULT or revealing contents of kernel memory.
 
 Patch against HEAD:
 
 Index: subr_mchain.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/kern/subr_mchain.c,v
 retrieving revision 1.4
 diff -u -r1.4 subr_mchain.c
 --- subr_mchain.c	2002/02/21 16:23:38	1.4
 +++ subr_mchain.c	2002/03/18 22:13:41
 @@ -273,8 +273,21 @@
  	long left;
  	int mtype, error;
  
 -	mtype = (uiop->uio_segflg == UIO_SYSSPACE) ? MB_MSYSTEM : MB_MUSER;
 -
 +	switch (uiop->uio_segflg) {
 +	case UIO_USERSPACE:
 +	case UIO_USERISPACE:
 +		mtype = MB_MUSER;
 +		break;
 +	case UIO_SYSSPACE:
 +		mtype = MB_MSYSTEM;
 +		break;
 +	case UIO_NOCOPY:
 +		/* XXX Not supported */
 +		return EOPNOTSUPP;
 +	default:
 +		return EINVAL;
 +	}
 + 
  	while (size > 0 && uiop->uio_resid) {
  		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  			return EFBIG;
 
 
 Patch against RELENG_4:
 
 Index: subr_mchain.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/kern/subr_mchain.c,v
 retrieving revision 1.2.2.1
 diff -u -r1.2.2.1 subr_mchain.c
 --- subr_mchain.c	2001/05/18 11:01:21	1.2.2.1
 +++ subr_mchain.c	2002/03/18 22:10:40
 @@ -525,7 +525,21 @@
  	long left;
  	int mtype, error;
  
 -	mtype = (uiop->uio_segflg == UIO_SYSSPACE) ? MB_MSYSTEM : MB_MUSER;
 +	switch (uiop->uio_segflg) {
 +	case UIO_USERSPACE:
 +	case UIO_USERISPACE:
 +		mtype = MB_MUSER;
 +		break;
 +	case UIO_SYSSPACE:
 +		mtype = MB_MSYSTEM;
 +		break;
 +	case UIO_NOCOPY:
 +		/* XXX Not supported */
 +		return EOPNOTSUPP;
 +	default:
 +		return EINVAL;
 +	}
 +
  	while (size > 0) {
  		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  			return EFBIG;
 
 
 Tim

From: Alfred Perlstein <bright@mu.org>
To: freebsd-gnats-submit@FreeBSD.org, tim@robbins.dropbear.id.au
Cc:  
Subject: Re: kern/36038
Date: Mon, 18 Mar 2002 14:53:02 -0800

 Can you try this delta?  Afaik UIO_NOCOPY means don't do anything
 other than updating the uio as if the data had been copied.
 
 Index: kern/subr_mchain.c
 ===================================================================
 RCS file: /home/ncvs/src/sys/kern/subr_mchain.c,v
 retrieving revision 1.4
 diff -u -r1.4 subr_mchain.c
 --- kern/subr_mchain.c	21 Feb 2002 16:23:38 -0000	1.4
 +++ kern/subr_mchain.c	18 Mar 2002 22:56:15 -0000
 @@ -497,6 +497,8 @@
  			while (count--)
  				*target++ = *s++;
  			continue;
 +		    case MB_NONE:
 +			break;
  		}
  		target += count;
  	}
 @@ -524,6 +526,20 @@
  	int mtype, error;
  
  	mtype = (uiop->uio_segflg == UIO_SYSSPACE) ? MB_MSYSTEM : MB_MUSER;
 +	switch (uiop->uio_segflg) {
 +	case UIO_USERSPACE:
 +	case UIO_USERISPACE:
 +		mtype = MB_MUSER;
 +		break;
 +	case UIO_SYSSPACE:
 +		mtype = MB_MSYSTEM;
 +		break;
 +	case UIO_NOCOPY:
 +		mtype = MB_NONE;
 +		break;
 +	default:
 +		return EINVAL;
 +	}
  	while (size > 0 && uiop->uio_resid) {
  		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
  			return EFBIG;
 Index: sys/mchain.h
 ===================================================================
 RCS file: /home/ncvs/src/sys/sys/mchain.h,v
 retrieving revision 1.3
 diff -u -r1.3 mchain.h
 --- sys/mchain.h	27 Feb 2002 17:15:50 -0000	1.3
 +++ sys/mchain.h	18 Mar 2002 22:59:06 -0000
 @@ -113,6 +113,7 @@
  #define MB_MINLINE	2		/* use an inline copy loop */
  #define	MB_MZERO	3		/* bzero(), mb_put_mem only */
  #define	MB_MCUSTOM	4		/* use an user defined function */
 +#define	MB_NONE		5		/* don't copy (UIO_NOCOPY) */
  
  struct mbuf;
  struct mbchain;
Responsible-Changed-From-To: freebsd-bugs->sheldonh 
Responsible-Changed-By: sheldonh 
Responsible-Changed-When: Wed Mar 20 04:43:05 PST 2002 
Responsible-Changed-Why:  
I'll hold on to this one as a reminder until I get feedback 
from bp and fjoe. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=36038 

From: Sheldon Hearn <sheldonh@starjuice.net>
To: Alfred Perlstein <bright@mu.org>
Cc: bug-followup@freebsd.org
Subject: Re: kern/36038: sendfile(2) on smbfs fails
Date: Wed, 20 Mar 2002 18:16:24 +0200

 Boris has looked at the PR, acknowledges the bug and the approach taken
 to work around it, but can't test the patch himself.
 
 So I think go ahead as soon as the originator confirms that it's good.
 
 Thanks, I'm pretty sure this closes at least one other PR, about ftpd
 and ntfs, if I'm not mistaken.  I'll have to hunt that one down.
 
 Ciao,
 Sheldon.

From: "Tim J. Robbins" <tim@robbins.dropbear.id.au>
To: Alfred Perlstein <bright@mu.org>
Cc: freebsd-gnats-submit@FreeBSD.org
Subject: Re: kern/36038
Date: Thu, 21 Mar 2002 16:47:32 +1100

 On Mon, Mar 18, 2002 at 02:53:02PM -0800, Alfred Perlstein wrote:
 
 > Can you try this delta?  Afaik UIO_NOCOPY means don't do anything
 > other than updating the uio as if the data had been copied.
 
 Sorry for taking so long to get back to you; no, the patch doesn't seem
 to help. I think the problem is that it doesn't set iov_base to point
 to the data. 
 
 I had no luck implementing proper UIO_NOCOPY support in subr_mchain.c
 (probably because I don't really know what I'm doing).
 
 I think returning EINVAL for the moment, until it's implemented correctly,
 is the best thing to do. At least ftpd detects this and falls back to normal
 read/write calls.
 
 
 Tim

From: "Tim J. Robbins" <tim@robbins.dropbear.id.au>
To: freebsd-gnats-submit@FreeBSD.ORG
Cc:  
Subject: kern/36038
Date: Thu, 21 Mar 2002 16:58:45 +1100

 It seems netncp is also broken:
                         if (uiop->uio_segflg == UIO_SYSSPACE)
                                 bcopy(mbufcp, uiocp, xfer);
                         else
                                 copyout(mbufcp, uiocp, xfer);
 
 and nfs:
                         if (uiop->uio_segflg == UIO_SYSSPACE)
                                 bcopy(mbufcp, uiocp, xfer);
                         else
                                 copyout(mbufcp, uiocp, xfer);
 
 perhaps cd9660:
         /*
          * Now get a buffer
          * Abuse a namei buffer for now.
          */
         if (uio->uio_segflg == UIO_SYSSPACE)
                 symname = uio->uio_iov->iov_base;
         else
                 symname = zalloc(namei_zone);
 
 
 
 Tim
Responsible-Changed-From-To: sheldonh->bp 
Responsible-Changed-By: sheldonh 
Responsible-Changed-When: Tue Apr 23 15:25:43 PDT 2002 
Responsible-Changed-Why:  
I was hoping to coordinate this, but haven't done anything useful with it 
in ages.  Perhaps Boris could take a look, as several PRs have been closed 
as duplicates of this one. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=36038 
State-Changed-From-To: open->patched 
State-Changed-By: tjr 
State-Changed-When: Wed Dec 18 22:38:47 PST 2002 
State-Changed-Why:  
sendfile() fails more gracefully on -current now. thttpd is still broken, 
but for a different reason (reading mmap'd region after close()). 

http://www.freebsd.org/cgi/query-pr.cgi?pr=36038 
Responsible-Changed-From-To: bp->freebsd-bugs 
Responsible-Changed-By: linimon 
Responsible-Changed-When: Mon Apr 17 21:01:28 UTC 2006 
Responsible-Changed-Why:  
Reassign at assignee's request due to current lack of time to work on FreeBSD. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=36038 
State-Changed-From-To: patched->closed 
State-Changed-By: maxim 
State-Changed-When: Mon Sep 18 19:08:50 UTC 2006 
State-Changed-Why:  
Fixed long time ago. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=36038 
>Unformatted:
