Skip site navigation (1)Skip section navigation (2)
Date:      Thu, 11 Nov 2010 23:03:06 GMT
From:      Bron Gondwana <brong@fastmail.fm>
To:        freebsd-gnats-submit@FreeBSD.org
Subject:   bin/152151: truss causes programs to open fd number 2, clobbering random files
Message-ID:  <201011112303.oABN362Z040540@www.freebsd.org>
Resent-Message-ID: <201011112310.oABNABaD025185@freefall.freebsd.org>

next in thread | raw e-mail | index | archive | help

>Number:         152151
>Category:       bin
>Synopsis:       truss causes programs to open fd number 2, clobbering random files
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Nov 11 23:10:11 UTC 2010
>Closed-Date:
>Last-Modified:
>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:
>Unformatted:



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