>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 [email protected]:/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...@\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:
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"