From nobody@FreeBSD.org  Thu Nov 11 23:03:06 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id C6C421065693
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 11 Nov 2010 23:03:06 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id B5DCB8FC1C
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 11 Nov 2010 23:03:06 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id oABN36RE040541
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 11 Nov 2010 23:03:06 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id oABN362Z040540;
	Thu, 11 Nov 2010 23:03:06 GMT
	(envelope-from nobody)
Message-Id: <201011112303.oABN362Z040540@www.freebsd.org>
Date: Thu, 11 Nov 2010 23:03:06 GMT
From: Bron Gondwana <brong@fastmail.fm>
To: freebsd-gnats-submit@FreeBSD.org
Subject: truss causes programs to open fd number 2, clobbering random files
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         152151
>Category:       bin
>Synopsis:       [patch] fix truss(1) causing programs to open fd number 2, clobbering random files
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Nov 11 23:10:11 UTC 2010
>Closed-Date:    Thu Nov 18 19:19:06 UTC 2010
>Last-Modified:  Thu Nov 18 19:19:06 UTC 2010
>Originator:     Bron Gondwana
>Release:        8.1
>Organization:
FastMail.FM
>Environment:
FreeBSD cyrus1.surfcloud.nl 8.1-RELEASE FreeBSD 8.1-RELEASE #0: Mon Jul 19 02:36:49 UTC 2010     root@mason.cse.buffalo.edu:/usr/obj/usr/src/sys/GENERIC  amd64
>Description:
Truss attempts to protect its output file from the environment:

	/*
	 * Set FD_CLOEXEC, so that the output file is not shared with
	 * the traced process.
	 */
	if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
		warn("fcntl()");


Unfortunately, this has the side effect of making the same fd available to the executed program.  Above, this was set to stderr.

         trussinfo->outfile = stderr;

So when the executed program later tries to report an issue to stderr, it gets written to whatever file was unlucky enough to be opened with fd 2.  The case that lead me to investigating this was a Cyrus IMAPd reconstruct program being run under truss causing the error code to be written right over the header of the main database.  Not cool.
>How-To-Repeat:
Here's a little test case someone on the #freebsd channel put together.

   1.
      monte-cristo!abbe:~ % truss ./test
   2.
      __sysctl(0x7fffffffe310,0x2,0x7fffffffe32c,0x7fffffffe320,0x0,0x0) = 0 (0x0)
   3.
      mmap(0x0,672,PROT_READ|PROT_WRITE,MAP_ANON,-1,0x0) = 34365177856 (0x800530000)
   4.
      munmap(0x800530000,672)                          = 0 (0x0)
   5.
      __sysctl(0x7fffffffe380,0x2,0x800639428,0x7fffffffe378,0x0,0x0) = 0 (0x0)
   6.
      mmap(0x0,32768,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_ANON,-1,0x0) = 34365177856 (0x800530000)
   7.
      issetugid(0x800531015,0x80052acc4,0x800645c50,0x800645c20,0x6351,0x0) = 0 (0x0)
   8.
      open("/etc/libmap.conf",O_RDONLY,0666)           ERR#2 'No such file or directory'
   9.
      open("/var/run/ld-elf.so.hints",O_RDONLY,057)    = 2 (0x2)
  10.
      read(2,"Ehnt\^A\0\0\0\M^@\0\0\0\M-*\0\0"...,128) = 128 (0x80)
  11.
      lseek(2,0x80,SEEK_SET)                           = 128 (0x80)
  12.
      read(2,"/lib:/usr/lib:/usr/lib/compat:/u"...,170) = 170 (0xaa)
  13.
      close(2)                                         = 0 (0x0)
  14.
      access("/lib/libc.so.7",0)                       = 0 (0x0)
  15.
      open("/lib/libc.so.7",O_RDONLY,030711400)        = 2 (0x2)
  16.
      fstat(2,{ mode=-r--r--r-- ,inode=23554,size=1270640,blksize=16384 }) = 0 (0x0)
  17.
      pread(0x2,0x8006382e0,0x1000,0x0,0x101010101010101,0x8080808080808080) = 4096 (0x1000)
  18.
      mmap(0x0,2342912,PROT_NONE,MAP_PRIVATE|MAP_ANON|MAP_NOCORE,-1,0x0) = 34366316544 (0x800646000)
  19.
      mmap(0x800646000,1056768,PROT_READ|PROT_EXEC,MAP_PRIVATE|MAP_FIXED|MAP_NOCORE,2,0x0) = 34366316544 (0x800646000)
  20.
      mmap(0x800848000,126976,PROT_READ|PROT_WRITE,MAP_PRIVATE|MAP_FIXED,2,0x102000) = 34368421888 (0x800848000)
  21.
      mprotect(0x800867000,110592,PROT_READ|PROT_WRITE) = 0 (0x0)
  22.
      close(2)                                         = 0 (0x0)
  23.
      sysarch(0x81,0x7fffffffe400,0x800535088,0x0,0xffffffffffce3530,0x800661e78) = 0 (0x0)
  24.
      mmap(0x0,192,PROT_READ|PROT_WRITE,MAP_ANON,-1,0x0) = 34365210624 (0x800538000)
  25.
      munmap(0x800538000,192)                          = 0 (0x0)
  26.
      mmap(0x0,43696,PROT_READ|PROT_WRITE,MAP_ANON,-1,0x0) = 34365210624 (0x800538000)
  27.
      munmap(0x800538000,43696)                        = 0 (0x0)
  28.
      sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
  29.
      sigprocmask(SIG_SETMASK,0x0,0x0)                 = 0 (0x0)
  30.
      __sysctl(0x7fffffffe3a0,0x2,0x80086da60,0x7fffffffe398,0x0,0x0) = 0 (0x0)
  31.
      sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
  32.
      sigprocmask(SIG_SETMASK,0x0,0x0)                 = 0 (0x0)
  33.
      open("/tmp/test.txt",O_RDWR|O_CREAT|O_TRUNC,0666) = 2 (0x2)
  34.
      write(2,"Cool\n",5)                              = 5 (0x5)
  35.
      close(2)                                         = 0 (0x0)
  36.
      sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
  37.
      sigprocmask(SIG_SETMASK,0x0,0x0)                 = 0 (0x0)
  38.
      sigprocmask(SIG_BLOCK,SIGHUP|SIGINT|SIGQUIT|SIGKILL|SIGPIPE|SIGALRM|SIGTERM|SIGURG|SIGSTOP|SIGTSTP|SIGCONT|SIGCHLD|SIGTTIN|SIGTTOU|SIGIO|SIGXCPU|SIGXFSZ|SIGVTALRM|SIGPROF|SIGWINCH|SIGINFO|SIGUSR1|SIGUSR2,0x0) = 0 (0x0)
  39.
      sigprocmask(SIG_SETMASK,0x0,0x0)                 = 0 (0x0)
  40.
      process exit, rval = 0
  41.
      monte-cristo!abbe:~ % cat /tmp/test.txt
  42.
      Cool
  43.
      monte-cristo!abbe:~ % cat test.c
  44.
      #include <stdio.h>
  45.
       
  46.
      int
  47.
      main()
  48.
      {
  49.
              FILE* fp;
  50.
       
  51.
              fp = fopen("/tmp/test.txt","w+");
  52.
              fprintf(stderr, "Cool\n");
  53.
              fclose(fp);
  54.
       
  55.
      }

>Fix:
I suspect you need to clone the stderr fd and write to the clone'd fd instead.  Strace on Linux and truss on Solaris both get it right.

>Release-Note:
>Audit-Trail:

From: ashish@FreeBSD.org (Ashish SHUKLA)
To: bug-followup@FreeBSD.org,brong@fastmail.fm
Cc:  
Subject: Re: bin/152151: truss causes programs to open fd number 2, clobbering random files
Date: Fri, 12 Nov 2010 05:27:00 +0530

 --=-=-=
 Content-Type: text/plain
 
 Hi,
 
 Attached diff (based on the hints mentioned by Bron) fixes the problem for me.
 
 HTH
 -- 
 Ashish SHUKLA      | GPG: F682 CDCC 39DC 0FEA E116  20B6 C746 CFA9 E74F A4B0
 freebsd.org!ashish | http://people.freebsd.org/~ashish/
 
 Avoid Success At All Costs !!
 
 --=-=-=
 Content-Type: text/plain
 Content-Disposition: attachment; filename=main.c.diff
 Content-Description: diff
 
 --- main.c~	2010-11-11 23:46:13.000000000 +0000
 +++ main.c	2010-11-11 23:55:11.000000000 +0000
 @@ -238,13 +238,14 @@
  	if (fname != NULL) { /* Use output file */
  		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
  			errx(1, "cannot open %s", fname);
 +	
 +		/*
 +		 * Set FD_CLOEXEC, so that the output file is not shared with
 +		 * the traced process.
 +		 */
 +		else if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 +			warn("fcntl()");
  	}
 -	/*
 -	 * Set FD_CLOEXEC, so that the output file is not shared with
 -	 * the traced process.
 -	 */
 -	if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 -		warn("fcntl()");
  
  	/*
  	 * If truss starts the process itself, it will ignore some signals --
 
 --=-=-=--
Responsible-Changed-From-To: freebsd-bugs->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Fri Nov 12 18:16:14 UTC 2010 
Responsible-Changed-Why:  
My bug 

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

From: Jaakko Heinonen <jh@FreeBSD.org>
To: Ashish SHUKLA <ashish@FreeBSD.org>, brong@fastmail.fm
Cc: bug-followup@FreeBSD.org
Subject: Re: bin/152151: truss causes programs to open fd number 2,
 clobbering random files
Date: Fri, 12 Nov 2010 20:13:24 +0200

 On 2010-11-12, Ashish SHUKLA wrote:
 >  Attached diff (based on the hints mentioned by Bron) fixes the problem for me.
 >  --- main.c~	2010-11-11 23:46:13.000000000 +0000
 >  +++ main.c	2010-11-11 23:55:11.000000000 +0000
 >  @@ -238,13 +238,14 @@
 >   	if (fname != NULL) { /* Use output file */
 >   		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
 >   			errx(1, "cannot open %s", fname);
 >  +	
 >  +		/*
 >  +		 * Set FD_CLOEXEC, so that the output file is not shared with
 >  +		 * the traced process.
 >  +		 */
 >  +		else if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 >  +			warn("fcntl()");
 >   	}
 >  -	/*
 >  -	 * Set FD_CLOEXEC, so that the output file is not shared with
 >  -	 * the traced process.
 >  -	 */
 >  -	if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 >  -		warn("fcntl()");
 >   
 >   	/*
 >   	 * If truss starts the process itself, it will ignore some signals --
 
 The patch looks good to me. Thanks!
 
 To PR submitter: Could you confirm that the patch fixes the problem for
 you?
 
 -- 
 Jaakko

From: "Bron Gondwana" <brong@fastmail.fm>
To: "Jaakko Heinonen" <jh@FreeBSD.org>, "Ashish SHUKLA"
 <ashish@FreeBSD.org>
Cc: bug-followup@FreeBSD.org
Subject: Re: bin/152151: truss causes programs to open fd number 2, clobbering
 random files
Date: Sat, 13 Nov 2010 14:39:54 +1100

 On Fri, 12 Nov 2010 20:13 +0200, "Jaakko Heinonen" <jh@FreeBSD.org> wrote:
 > On 2010-11-12, Ashish SHUKLA wrote:
 > >  Attached diff (based on the hints mentioned by Bron) fixes the problem for me.
 > >  --- main.c~	2010-11-11 23:46:13.000000000 +0000
 > >  +++ main.c	2010-11-11 23:55:11.000000000 +0000
 > >  @@ -238,13 +238,14 @@
 > >   	if (fname != NULL) { /* Use output file */
 > >   		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
 > >   			errx(1, "cannot open %s", fname);
 > >  +	
 > >  +		/*
 > >  +		 * Set FD_CLOEXEC, so that the output file is not shared with
 > >  +		 * the traced process.
 > >  +		 */
 > >  +		else if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 > >  +			warn("fcntl()");
 > >   	}
 > >  -	/*
 > >  -	 * Set FD_CLOEXEC, so that the output file is not shared with
 > >  -	 * the traced process.
 > >  -	 */
 > >  -	if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 > >  -		warn("fcntl()");
 > >   
 > >   	/*
 > >   	 * If truss starts the process itself, it will ignore some signals --
 > 
 > The patch looks good to me. Thanks!
 > 
 > To PR submitter: Could you confirm that the patch fixes the problem for
 > you?
 
 Sorry, I don't actually have a FreeBSD box of my own - I was using a virtual
 machine set up by a Cyrus user on the far side of the world to try and track
 down a problem he was having!
 
 That said, if you can confirm that ls is opening fd 3 rather than fd 2 then
 I believe you :)  The patch certainly looks fine.
 
 Bron ( you'll get real stdout data mixed with your logs - but that's not
        too bad - better to change to logging to a file for that than because
        you were corrupting random files! )
 -- 
   Bron Gondwana
   brong@fastmail.fm
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/152151: commit references a PR
Date: Sat, 13 Nov 2010 09:28:54 +0000 (UTC)

 Author: jh
 Date: Sat Nov 13 09:28:49 2010
 New Revision: 215235
 URL: http://svn.freebsd.org/changeset/base/215235
 
 Log:
   Set FD_CLOEXEC for the output file only when the file has been specified
   with the -o option. Setting the flag for stderr (the default) could
   cause the traced process to redirect stderr to a random file.
   
   PR:		bin/152151
   Submitted by:	ashish
   MFC after:	5 days
 
 Modified:
   head/usr.bin/truss/main.c
 
 Modified: head/usr.bin/truss/main.c
 ==============================================================================
 --- head/usr.bin/truss/main.c	Sat Nov 13 08:58:36 2010	(r215234)
 +++ head/usr.bin/truss/main.c	Sat Nov 13 09:28:49 2010	(r215235)
 @@ -241,13 +241,14 @@ main(int ac, char **av)
  	if (fname != NULL) { /* Use output file */
  		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
  			errx(1, "cannot open %s", fname);
 +		/*
 +		 * Set FD_CLOEXEC, so that the output file is not shared with
 +		 * the traced process.
 +		 */
 +		if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) ==
 +		    -1)
 +			warn("fcntl()");
  	}
 -	/*
 -	 * Set FD_CLOEXEC, so that the output file is not shared with
 -	 * the traced process.
 -	 */
 -	if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 -		warn("fcntl()");
  
  	/*
  	 * If truss starts the process itself, it will ignore some signals --
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: jh 
State-Changed-When: Sat Nov 13 09:38:48 UTC 2010 
State-Changed-Why:  
Patched in head (r215235). Thanks for the report! 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/152151: commit references a PR
Date: Thu, 18 Nov 2010 19:07:02 +0000 (UTC)

 Author: jh
 Date: Thu Nov 18 19:06:56 2010
 New Revision: 215466
 URL: http://svn.freebsd.org/changeset/base/215466
 
 Log:
   MFC r215235:
   
   Set FD_CLOEXEC for the output file only when the file has been specified
   with the -o option. Setting the flag for stderr (the default) could
   cause the traced process to redirect stderr to a random file.
   
   PR:		bin/152151
 
 Modified:
   stable/8/usr.bin/truss/main.c
 Directory Properties:
   stable/8/usr.bin/truss/   (props changed)
 
 Modified: stable/8/usr.bin/truss/main.c
 ==============================================================================
 --- stable/8/usr.bin/truss/main.c	Thu Nov 18 18:49:04 2010	(r215465)
 +++ stable/8/usr.bin/truss/main.c	Thu Nov 18 19:06:56 2010	(r215466)
 @@ -238,13 +238,14 @@ main(int ac, char **av)
  	if (fname != NULL) { /* Use output file */
  		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
  			errx(1, "cannot open %s", fname);
 +		/*
 +		 * Set FD_CLOEXEC, so that the output file is not shared with
 +		 * the traced process.
 +		 */
 +		if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) ==
 +		    -1)
 +			warn("fcntl()");
  	}
 -	/*
 -	 * Set FD_CLOEXEC, so that the output file is not shared with
 -	 * the traced process.
 -	 */
 -	if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 -		warn("fcntl()");
  
  	/*
  	 * If truss starts the process itself, it will ignore some signals --
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/152151: commit references a PR
Date: Thu, 18 Nov 2010 19:09:04 +0000 (UTC)

 Author: jh
 Date: Thu Nov 18 19:08:56 2010
 New Revision: 215467
 URL: http://svn.freebsd.org/changeset/base/215467
 
 Log:
   MFC r215235:
   
   Set FD_CLOEXEC for the output file only when the file has been specified
   with the -o option. Setting the flag for stderr (the default) could
   cause the traced process to redirect stderr to a random file.
   
   PR:		bin/152151
 
 Modified:
   stable/7/usr.bin/truss/main.c
 Directory Properties:
   stable/7/usr.bin/truss/   (props changed)
 
 Modified: stable/7/usr.bin/truss/main.c
 ==============================================================================
 --- stable/7/usr.bin/truss/main.c	Thu Nov 18 19:06:56 2010	(r215466)
 +++ stable/7/usr.bin/truss/main.c	Thu Nov 18 19:08:56 2010	(r215467)
 @@ -230,13 +230,14 @@ main(int ac, char **av)
  	if (fname != NULL) { /* Use output file */
  		if ((trussinfo->outfile = fopen(fname, "w")) == NULL)
  			errx(1, "cannot open %s", fname);
 +		/*
 +		 * Set FD_CLOEXEC, so that the output file is not shared with
 +		 * the traced process.
 +		 */
 +		if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) ==
 +		    -1)
 +			warn("fcntl()");
  	}
 -	/*
 -	 * Set FD_CLOEXEC, so that the output file is not shared with
 -	 * the traced process.
 -	 */
 -	if (fcntl(fileno(trussinfo->outfile), F_SETFD, FD_CLOEXEC) == -1)
 -		warn("fcntl()");
  
  	/*
  	 * If truss starts the process itself, it will ignore some signals --
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jh 
State-Changed-When: Thu Nov 18 19:19:05 UTC 2010 
State-Changed-Why:  
Fixed in all affected branches. 

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