bin/152151: truss causes programs to open fd number 2, clobbering random files

Bron Gondwana brong at fastmail.fm
Thu Nov 11 23:10:11 UTC 2010


>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 at 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:


More information about the freebsd-bugs mailing list