• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===-- FDInterposing.cpp ---------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file helps with catching double close calls on unix integer file
11 // descriptors by interposing functions for all file descriptor create and
12 // close operations. A stack backtrace for every create and close function is
13 // maintained, and every create and close operation is logged. When a double
14 // file descriptor close is encountered, it will be logged.
15 //
16 // To enable the interposing in a darwin program, set the DYLD_INSERT_LIBRARIES
17 // environment variable as follows:
18 // For sh:
19 //  DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib /path/to/executable
20 // For tcsh:
21 //  (setenv DYLD_INSERT_LIBRARIES=/path/to/FDInterposing.dylib ; /path/to/executable)
22 //
23 // Other environment variables that can alter the default actions of this
24 // interposing shared library include:
25 //
26 // "FileDescriptorStackLoggingNoCompact"
27 //
28 //      With this environment variable set, all file descriptor create and
29 //      delete operations will be permanantly maintained in the event map.
30 //      The default action is to compact the create/delete events by removing
31 //      any previous file descriptor create events that are matched with a
32 //      corresponding file descriptor delete event when the next valid file
33 //      descriptor create event is detected.
34 //
35 // "FileDescriptorMinimalLogging"
36 //
37 //      By default every file descriptor create and delete operation is logged
38 //      (to STDOUT by default, see the "FileDescriptorLogFile"). This can be
39 //      suppressed to only show errors and warnings by setting this environment
40 //      variable (the value in not important).
41 //
42 // "FileDescriptorLogFile=<path>"
43 //
44 //      By default logging goes to STDOUT_FILENO, but this can be changed by
45 //      setting FileDescriptorLogFile. The value is a path to a file that
46 //      will be opened and used for logging.
47 //===----------------------------------------------------------------------===//
48 
49 #include <assert.h>
50 #include <dirent.h>
51 #include <errno.h>
52 #include <fcntl.h>
53 #include <execinfo.h>
54 #include <libgen.h>
55 #include <mach-o/dyld.h>
56 #include <mach-o/dyld-interposing.h>
57 #include <stdlib.h>
58 #include <stdio.h>
59 #include <string.h>
60 #include <sys/event.h>
61 #include <sys/mman.h>
62 #include <sys/socket.h>
63 #include <sys/types.h>
64 #include <sys/time.h>
65 #include <tr1/memory> // for std::tr1::shared_ptr
66 #include <unistd.h>
67 #include <string>
68 #include <vector>
69 #include <map>
70 
71 //----------------------------------------------------------------------
72 /// @def DISALLOW_COPY_AND_ASSIGN(TypeName)
73 ///     Macro definition for easily disallowing copy constructor and
74 ///     assignment operators in C++ classes.
75 //----------------------------------------------------------------------
76 #define DISALLOW_COPY_AND_ASSIGN(TypeName) \
77 TypeName(const TypeName&); \
78 const TypeName& operator=(const TypeName&)
79 
80 extern "C" {
81     int accept$NOCANCEL (int, struct sockaddr * __restrict, socklen_t * __restrict);
82     int close$NOCANCEL(int);
83     int open$NOCANCEL(const char *, int, ...);
84     int __open_extended(const char *, int, uid_t, gid_t, int, struct kauth_filesec *);
85 }
86 
87 namespace fd_interposing {
88 
89 //----------------------------------------------------------------------
90 // String class so we can get formatted strings without having to worry
91 // about the memory storage since it will allocate the memory it needs.
92 //----------------------------------------------------------------------
93 class String
94 {
95 public:
String()96     String () :
97         m_str (NULL)
98     {}
99 
String(const char * format,...)100     String (const char *format, ...) :
101         m_str (NULL)
102     {
103         va_list args;
104         va_start (args, format);
105         vprintf (format, args);
106         va_end (args);
107     }
108 
~String()109     ~String()
110     {
111         reset();
112     }
113 
114     void
reset(char * s=NULL)115     reset (char *s = NULL)
116     {
117         if (m_str)
118             ::free (m_str);
119         m_str = s;
120     }
121 
122     const char *
c_str() const123     c_str () const
124     {
125         return m_str;
126     }
127 
128     void
printf(const char * format,...)129     printf (const char *format, ...)
130     {
131         va_list args;
132         va_start (args, format);
133         vprintf (format, args);
134         va_end (args);
135     }
136     void
vprintf(const char * format,va_list args)137     vprintf (const char *format, va_list args)
138     {
139         reset();
140         ::vasprintf (&m_str, format, args);
141     }
142 
143     void
log(int log_fd)144     log (int log_fd)
145     {
146         if (m_str && log_fd >= 0)
147         {
148             const int len = strlen(m_str);
149             if (len > 0)
150             {
151                 write (log_fd, m_str, len);
152                 const char last_char = m_str[len-1];
153                 if (!(last_char == '\n' || last_char == '\r'))
154                     write (log_fd, "\n", 1);
155             }
156         }
157     }
158 protected:
159     char *m_str;
160 
161 private:
162     DISALLOW_COPY_AND_ASSIGN (String);
163 };
164 
165 //----------------------------------------------------------------------
166 // Type definitions
167 //----------------------------------------------------------------------
168 typedef std::vector<void *> Frames;
169 class FDEvent;
170 typedef std::vector<void *> Frames;
171 typedef std::tr1::shared_ptr<FDEvent> FDEventSP;
172 typedef std::tr1::shared_ptr<String> StringSP;
173 
174 
175 //----------------------------------------------------------------------
176 // FDEvent
177 //
178 // A class that describes a file desciptor event.
179 //
180 // File descriptor events fall into one of two categories: create events
181 // and delete events.
182 //----------------------------------------------------------------------
183 class FDEvent
184 {
185 public:
FDEvent(int fd,int err,const StringSP & string_sp,bool is_create,const Frames & frames)186     FDEvent (int fd, int err, const StringSP &string_sp, bool is_create, const Frames& frames) :
187         m_string_sp (string_sp),
188         m_frames (frames.begin(), frames.end()),
189         m_fd (fd),
190         m_err (err),
191         m_is_create (is_create)
192     {}
193 
~FDEvent()194     ~FDEvent () {}
195 
196     bool
IsCreateEvent() const197     IsCreateEvent() const
198     {
199         return m_is_create;
200     }
201 
202     bool
IsDeleteEvent() const203     IsDeleteEvent() const
204     {
205         return !m_is_create;
206     }
207 
208     Frames &
GetFrames()209     GetFrames ()
210     {
211         return m_frames;
212     }
213 
214     const Frames &
GetFrames() const215     GetFrames () const
216     {
217         return m_frames;
218     }
219 
220     int
GetFD() const221     GetFD () const
222     {
223         return m_fd;
224     }
225 
226     int
GetError() const227     GetError () const
228     {
229         return m_err;
230     }
231 
232     void
233     Dump (int log_fd) const;
234 
235     void
SetCreateEvent(FDEventSP & create_event_sp)236     SetCreateEvent (FDEventSP &create_event_sp)
237     {
238         m_create_event_sp = create_event_sp;
239     }
240 
241 private:
242     // A shared pointer to a String that describes this event in
243     // detail (all args and return and error values)
244     StringSP m_string_sp;
245     // The frames for the stack backtrace for this event
246     Frames m_frames;
247     // If this is a file descriptor delete event, this might contain
248     // the correspoding file descriptor create event
249     FDEventSP m_create_event_sp;
250     // The file descriptor for this event
251     int m_fd;
252     // The error code (if any) for this event
253     int m_err;
254     // True if this event is a file descriptor create event, false
255     // if it is a file descriptor delete event
256     bool m_is_create;
257 };
258 
259 //----------------------------------------------------------------------
260 // Templatized class that will save errno only if the "value" it is
261 // constructed with is equal to INVALID. When the class goes out of
262 // scope, it will restore errno if it was saved.
263 //----------------------------------------------------------------------
264 template <int INVALID>
265 class Errno
266 {
267 public:
268     // Save errno only if we are supposed to
Errno(int value)269     Errno (int value) :
270         m_saved_errno ((value == INVALID) ? errno : 0),
271         m_restore (value == INVALID)
272     {
273     }
274 
275     // Restore errno only if we are supposed to
~Errno()276     ~Errno()
277     {
278         if (m_restore)
279             errno = m_saved_errno;
280     }
281 
282     // Accessor for the saved value of errno
283     int
get_errno() const284     get_errno() const
285     {
286         return m_saved_errno;
287     }
288 
289 protected:
290     const int m_saved_errno;
291     const bool m_restore;
292 };
293 
294 typedef Errno<-1> InvalidFDErrno;
295 typedef Errno<-1> NegativeErrorErrno;
296 typedef std::vector<FDEventSP> FDEventArray;
297 typedef std::map<int, FDEventArray> FDEventMap;
298 
299 //----------------------------------------------------------------------
300 // Globals
301 //----------------------------------------------------------------------
302 // Global event map that contains all file descriptor events. As file
303 // descriptor create and close events come in, they will get filled
304 // into this map (protected by g_mutex). When a file descriptor close
305 // event is detected, the open event will be removed and placed into
306 // the close event so if something tries to double close a file
307 // descriptor we can show the previous close event and the file
308 // desctiptor event that created it. When a new file descriptor create
309 // event comes in, we will remove the previous one for that file
310 // desctiptor unless the environment variable "FileDescriptorStackLoggingNoCompact"
311 // is set. The file desctiptor history can be accessed using the
312 // get_fd_history() function.
313 static FDEventMap g_fd_event_map;
314 // A mutex to protect access to our data structures in g_fd_event_map
315 // and also our logging messages
316 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
317 // Log all file descriptor create and close events by default. Only log
318 // warnings and erros if the "FileDescriptorMinimalLogging" environment
319 // variable is set.
320 static int g_log_all_calls = 1;
321 // We compact the file descriptor events by default. Set the environment
322 // varible "FileDescriptorStackLoggingNoCompact" to keep a full history.
323 static int g_compact = 1;
324 // The current process ID
325 static int g_pid = -1;
326 static bool g_enabled = true;
327 //----------------------------------------------------------------------
328 // Mutex class that will lock a mutex when it is constructed, and unlock
329 // it when is goes out of scope
330 //----------------------------------------------------------------------
331 class Locker
332 {
333 public:
Locker(pthread_mutex_t * mutex_ptr)334     Locker (pthread_mutex_t *mutex_ptr) :
335         m_mutex_ptr(mutex_ptr)
336     {
337         ::pthread_mutex_lock (m_mutex_ptr);
338     }
339 
340     // This allows clients to test try and acquire the mutex...
Locker(pthread_mutex_t * mutex_ptr,bool & lock_acquired)341     Locker (pthread_mutex_t *mutex_ptr, bool &lock_acquired) :
342         m_mutex_ptr(NULL)
343     {
344         lock_acquired = ::pthread_mutex_trylock(mutex_ptr) == 0;
345         if (lock_acquired)
346             m_mutex_ptr = mutex_ptr;
347     }
348 
~Locker()349     ~Locker ()
350     {
351         if (m_mutex_ptr)
352             ::pthread_mutex_unlock (m_mutex_ptr);
353     }
354 protected:
355     pthread_mutex_t *m_mutex_ptr;
356 };
357 
358 static void
359 log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
360 
361 static void
362 log (int log_fd, const FDEvent *event, const char *format, ...) __attribute__ ((format (printf, 3, 4)));
363 
364 static void
365 backtrace_log (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
366 
367 static void
368 backtrace_error (const char *format, ...) __attribute__ ((format (printf, 1, 2)));
369 
370 static void
371 log_to_fd (int log_fd, const char *format, ...) __attribute__ ((format (printf, 2, 3)));
372 
373 static inline size_t
get_backtrace(Frames & frame_buffer,size_t frames_to_remove)374 get_backtrace (Frames &frame_buffer, size_t frames_to_remove)
375 {
376     void *frames[2048];
377     int count = ::backtrace (&frames[0], sizeof(frames)/sizeof(void*));
378     if (count > frames_to_remove)
379         frame_buffer.assign (&frames[frames_to_remove], &frames[count]);
380     else
381         frame_buffer.assign (&frames[0], &frames[count]);
382     while (frame_buffer.back() < (void *)1024)
383         frame_buffer.pop_back();
384     return frame_buffer.size();
385 }
386 
387 static int g_log_fd = STDOUT_FILENO;
388 static int g_initialized = 0;
389 
390 const char *
get_process_fullpath(bool force=false)391 get_process_fullpath (bool force = false)
392 {
393     static char g_process_fullpath[PATH_MAX] = {0};
394     if (force || g_process_fullpath[0] == '\0')
395     {
396         // If DST is NULL, then return the number of bytes needed.
397         uint32_t len = sizeof(g_process_fullpath);
398         if (_NSGetExecutablePath (g_process_fullpath, &len) != 0)
399             strncpy (g_process_fullpath, "<error>", sizeof(g_process_fullpath));
400     }
401     return g_process_fullpath;
402 }
403 
404 // Returns the current process ID, or -1 if inserposing not enabled for
405 // this process
406 static int
get_interposed_pid()407 get_interposed_pid()
408 {
409     if (!g_enabled)
410         return -1;
411 
412     const pid_t pid = getpid();
413     if (g_pid != pid)
414     {
415         if (g_pid == -1)
416         {
417             g_pid = pid;
418             log ("Interposing file descriptor create and delete functions for %s (pid=%i)\n", get_process_fullpath (true), pid);
419         }
420         else
421         {
422             log ("pid=%i: disabling interposing file descriptor create and delete functions for child process %s (pid=%i)\n", g_pid, get_process_fullpath (true), pid);
423             g_enabled = false;
424             return -1;
425         }
426         // Log when our process changes
427     }
428     return g_pid;
429 }
430 
431 static int
get_logging_fd()432 get_logging_fd ()
433 {
434     if (!g_enabled)
435         return -1;
436 
437     if (!g_initialized)
438     {
439         g_initialized = 1;
440 
441         const pid_t pid = get_interposed_pid();
442 
443         if (g_enabled)
444         {
445             // Keep all stack info around for all fd create and delete calls.
446             // Otherwise we will remove the fd create call when a corresponding
447             // fd delete call is received
448             if (getenv("FileDescriptorStackLoggingNoCompact"))
449                 g_compact = 0;
450 
451             if (getenv("FileDescriptorMinimalLogging"))
452                 g_log_all_calls = 0;
453 
454             const char *log_path = getenv ("FileDescriptorLogFile");
455             if (log_path)
456                 g_log_fd = ::creat (log_path, 0660);
457             else
458                 g_log_fd = STDOUT_FILENO;
459 
460             // Only let this interposing happen on the first time this matches
461             // and stop this from happening so any child processes don't also
462             // log their file descriptors
463             ::unsetenv ("DYLD_INSERT_LIBRARIES");
464         }
465         else
466         {
467             log ("pid=%i: logging disabled\n", getpid());
468         }
469     }
470     return g_log_fd;
471 }
472 
473 void
log_to_fd(int log_fd,const char * format,va_list args)474 log_to_fd (int log_fd, const char *format, va_list args)
475 {
476     if (format && format[0] && log_fd >= 0)
477     {
478         char buffer[PATH_MAX];
479         const int count = ::vsnprintf (buffer, sizeof(buffer), format, args);
480         if (count > 0)
481             write (log_fd, buffer, count);
482     }
483 }
484 
485 void
log_to_fd(int log_fd,const char * format,...)486 log_to_fd (int log_fd, const char *format, ...)
487 {
488     if (format && format[0])
489     {
490         va_list args;
491         va_start (args, format);
492         log_to_fd (log_fd, format, args);
493         va_end (args);
494     }
495 }
496 
497 void
log(const char * format,va_list args)498 log (const char *format, va_list args)
499 {
500     log_to_fd (get_logging_fd (), format, args);
501 }
502 
503 void
log(const char * format,...)504 log (const char *format, ...)
505 {
506     if (format && format[0])
507     {
508         va_list args;
509         va_start (args, format);
510         log (format, args);
511         va_end (args);
512     }
513 }
514 
515 void
log(int log_fd,const FDEvent * event,const char * format,...)516 log (int log_fd, const FDEvent *event, const char *format, ...)
517 {
518     if (format && format[0])
519     {
520         va_list args;
521         va_start (args, format);
522         log_to_fd (log_fd, format, args);
523         va_end (args);
524     }
525     if (event)
526         event->Dump(log_fd);
527 }
528 
529 void
Dump(int log_fd) const530 FDEvent::Dump (int log_fd) const
531 {
532     if (log_fd >= 0)
533     {
534         log_to_fd (log_fd, "%s\n", m_string_sp->c_str());
535         if (!m_frames.empty())
536             ::backtrace_symbols_fd (m_frames.data(), m_frames.size(), log_fd);
537 
538         if (m_create_event_sp)
539         {
540             log_to_fd (log_fd, "\nfd=%i was created with this event:\n", m_fd);
541             m_create_event_sp->Dump (log_fd);
542             log_to_fd (log_fd, "\n");
543         }
544     }
545 }
546 
547 
548 void
backtrace_log(const char * format,...)549 backtrace_log (const char *format, ...)
550 {
551     const int log_fd = get_logging_fd ();
552     if (log_fd >= 0)
553     {
554         if (format && format[0])
555         {
556             va_list args;
557             va_start (args, format);
558             log (format, args);
559             va_end (args);
560         }
561 
562         Frames frames;
563         if (get_backtrace(frames, 2))
564             ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
565     }
566 
567 }
568 
569 void
backtrace_error(const char * format,...)570 backtrace_error (const char *format, ...)
571 {
572     const int pid = get_interposed_pid();
573     if (pid >= 0)
574     {
575         const int log_fd = get_logging_fd ();
576         if (log_fd >= 0)
577         {
578             log ("\nerror: %s (pid=%i): ", get_process_fullpath (), pid);
579 
580             if (format && format[0])
581             {
582                 va_list args;
583                 va_start (args, format);
584                 log (format, args);
585                 va_end (args);
586             }
587 
588             Frames frames;
589             if (get_backtrace(frames, 2))
590                 ::backtrace_symbols_fd (frames.data(), frames.size(), log_fd);
591         }
592     }
593 }
594 
595 void
save_backtrace(int fd,int err,const StringSP & string_sp,bool is_create)596 save_backtrace (int fd, int err, const StringSP &string_sp, bool is_create)
597 {
598     Frames frames;
599     get_backtrace(frames, 2);
600 
601     FDEventSP fd_event_sp (new FDEvent (fd, err, string_sp, is_create, frames));
602 
603     FDEventMap::iterator pos = g_fd_event_map.find (fd);
604 
605     if (pos != g_fd_event_map.end())
606     {
607         // We have history for this fd...
608 
609         FDEventArray &event_array = g_fd_event_map[fd];
610         if (fd_event_sp->IsCreateEvent())
611         {
612             // The current fd event is a function that creates
613             // a descriptor, check in case last event was
614             // a create event.
615             if (event_array.back()->IsCreateEvent())
616             {
617                 const int log_fd = get_logging_fd();
618                 // Two fd create functions in a row, we missed
619                 // a function that closes a fd...
620                 log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor create event fd=%i (we missed a file descriptor close event):\n", fd);
621             }
622             else if (g_compact)
623             {
624                 // We are compacting so we remove previous create event
625                 // when we get the correspinding delete event
626                 event_array.pop_back();
627             }
628         }
629         else
630         {
631             // The current fd event is a function that deletes
632             // a descriptor, check in case last event for this
633             // fd was a delete event (double close!)
634             if (event_array.back()->IsDeleteEvent())
635             {
636                 const int log_fd = get_logging_fd();
637                 // Two fd delete functions in a row, we must
638                 // have missed some function that opened a descriptor
639                 log (log_fd, fd_event_sp.get(), "\nwarning: unmatched file descriptor close event for fd=%d (we missed the file descriptor create event):\n", fd);
640             }
641             else if (g_compact)
642             {
643                 // Since this is a close event, we want to remember the open event
644                 // that this close if for...
645                 fd_event_sp->SetCreateEvent(event_array.back());
646                 // We are compacting so we remove previous create event
647                 // when we get the correspinding delete event
648                 event_array.pop_back();
649             }
650         }
651 
652         event_array.push_back(fd_event_sp);
653     }
654     else
655     {
656         g_fd_event_map[fd].push_back(fd_event_sp);
657     }
658 }
659 
660 //----------------------------------------------------------------------
661 // socket() interpose function
662 //----------------------------------------------------------------------
663 extern "C" int
socket$__interposed__(int domain,int type,int protocol)664 socket$__interposed__ (int domain, int type, int protocol)
665 {
666     const int pid = get_interposed_pid();
667     if (pid >= 0)
668     {
669         Locker locker (&g_mutex);
670         const int fd = ::socket (domain, type, protocol);
671         InvalidFDErrno fd_errno(fd);
672         StringSP description_sp(new String);
673         if (fd == -1)
674             description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i  errno = %i", pid, domain, type, protocol, fd, fd_errno.get_errno());
675         else
676             description_sp->printf("pid=%i: socket (domain = %i, type = %i, protocol = %i) => fd=%i", pid, domain, type, protocol, fd);
677         if (g_log_all_calls)
678             description_sp->log (get_logging_fd());
679         if (fd >= 0)
680             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
681         return fd;
682     }
683     else
684     {
685         return ::socket (domain, type, protocol);
686     }
687 }
688 
689 //----------------------------------------------------------------------
690 // socketpair() interpose function
691 //----------------------------------------------------------------------
692 extern "C" int
socketpair$__interposed__(int domain,int type,int protocol,int fds[2])693 socketpair$__interposed__ (int domain, int type, int protocol, int fds[2])
694 {
695     const int pid = get_interposed_pid();
696     if (pid >= 0)
697     {
698         Locker locker (&g_mutex);
699         fds[0] = -1;
700         fds[1] = -1;
701         const int err = socketpair (domain, type, protocol, fds);
702         NegativeErrorErrno err_errno(err);
703         StringSP description_sp(new String ("pid=%i: socketpair (domain=%i, type=%i, protocol=%i, {fd=%i, fd=%i}) -> err=%i", pid, domain, type, protocol, fds[0], fds[1], err));
704         if (g_log_all_calls)
705             description_sp->log (get_logging_fd());
706         if (fds[0] >= 0)
707             save_backtrace (fds[0], err_errno.get_errno(), description_sp, true);
708         if (fds[1] >= 0)
709             save_backtrace (fds[1], err_errno.get_errno(), description_sp, true);
710         return err;
711     }
712     else
713     {
714         return socketpair (domain, type, protocol, fds);
715     }
716 }
717 
718 //----------------------------------------------------------------------
719 // open() interpose function
720 //----------------------------------------------------------------------
721 extern "C" int
open$__interposed__(const char * path,int oflag,int mode)722 open$__interposed__ (const char *path, int oflag, int mode)
723 {
724     const int pid = get_interposed_pid();
725     if (pid >= 0)
726     {
727         Locker locker (&g_mutex);
728         int fd = -2;
729         StringSP description_sp(new String);
730         if (oflag & O_CREAT)
731         {
732             fd = ::open (path, oflag, mode);
733             description_sp->printf("pid=%i: open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd);
734         }
735         else
736         {
737             fd = ::open (path, oflag);
738             description_sp->printf("pid=%i: open (path = '%s', oflag = %i) -> fd=%i", pid, path, oflag, fd);
739         }
740 
741         InvalidFDErrno fd_errno(fd);
742         if (g_log_all_calls)
743             description_sp->log (get_logging_fd());
744         if (fd >= 0)
745             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
746         return fd;
747     }
748     else
749     {
750         return ::open (path, oflag, mode);
751     }
752 }
753 
754 //----------------------------------------------------------------------
755 // open$NOCANCEL() interpose function
756 //----------------------------------------------------------------------
757 extern "C" int
open$NOCANCEL$__interposed__(const char * path,int oflag,int mode)758 open$NOCANCEL$__interposed__ (const char *path, int oflag, int mode)
759 {
760     const int pid = get_interposed_pid();
761     if (pid >= 0)
762     {
763         Locker locker (&g_mutex);
764         const int fd = ::open$NOCANCEL (path, oflag, mode);
765         InvalidFDErrno fd_errno(fd);
766         StringSP description_sp(new String ("pid=%i: open$NOCANCEL (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd));
767         if (g_log_all_calls)
768             description_sp->log (get_logging_fd());
769         if (fd >= 0)
770             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
771         return fd;
772     }
773     else
774     {
775         return ::open$NOCANCEL (path, oflag, mode);
776     }
777 }
778 
779 
780 //----------------------------------------------------------------------
781 // __open_extended() interpose function
782 //----------------------------------------------------------------------
783 extern "C" int
__open_extended$__interposed__(const char * path,int oflag,uid_t uid,gid_t gid,int mode,struct kauth_filesec * fsacl)784 __open_extended$__interposed__ (const char *path, int oflag, uid_t uid, gid_t gid, int mode, struct kauth_filesec *fsacl)
785 {
786     const int pid = get_interposed_pid();
787     if (pid >= 0)
788     {
789         Locker locker (&g_mutex);
790         const int fd = ::__open_extended (path, oflag, uid, gid, mode, fsacl);
791         InvalidFDErrno fd_errno(fd);
792         StringSP description_sp(new String ("pid=%i: __open_extended (path='%s', oflag=%i, uid=%i, gid=%i, mode=%i, fsacl=%p) -> fd=%i", pid, path, oflag, uid, gid, mode, fsacl, fd));
793         if (g_log_all_calls)
794             description_sp->log (get_logging_fd());
795         if (fd >= 0)
796             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
797         return fd;
798     }
799     else
800     {
801         return ::__open_extended (path, oflag, uid, gid, mode, fsacl);
802     }
803 }
804 
805 //----------------------------------------------------------------------
806 // kqueue() interpose function
807 //----------------------------------------------------------------------
808 extern "C" int
kqueue$__interposed__(void)809 kqueue$__interposed__ (void)
810 {
811     const int pid = get_interposed_pid();
812     if (pid >= 0)
813     {
814         Locker locker (&g_mutex);
815         const int fd = ::kqueue ();
816         InvalidFDErrno fd_errno(fd);
817         StringSP description_sp(new String ("pid=%i: kqueue () -> fd=%i", pid, fd));
818         if (g_log_all_calls)
819             description_sp->log (get_logging_fd());
820         if (fd >= 0)
821             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
822         return fd;
823     }
824     else
825     {
826         return ::kqueue ();
827     }
828 }
829 
830 //----------------------------------------------------------------------
831 // shm_open() interpose function
832 //----------------------------------------------------------------------
833 extern "C" int
shm_open$__interposed__(const char * path,int oflag,int mode)834 shm_open$__interposed__ (const char *path, int oflag, int mode)
835 {
836     const int pid = get_interposed_pid();
837     if (pid >= 0)
838     {
839         Locker locker (&g_mutex);
840         const int fd = ::shm_open (path, oflag, mode);
841         InvalidFDErrno fd_errno(fd);
842         StringSP description_sp(new String ("pid=%i: shm_open (path = '%s', oflag = %i, mode = %i) -> fd=%i", pid, path, oflag, mode, fd));
843         if (g_log_all_calls)
844             description_sp->log (get_logging_fd());
845         if (fd >= 0)
846             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
847         return fd;
848     }
849     else
850     {
851         return ::shm_open (path, oflag, mode);
852     }
853 }
854 
855 //----------------------------------------------------------------------
856 // accept() interpose function
857 //----------------------------------------------------------------------
858 extern "C" int
accept$__interposed__(int socket,struct sockaddr * address,socklen_t * address_len)859 accept$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
860 {
861     const int pid = get_interposed_pid();
862     if (pid >= 0)
863     {
864         Locker locker (&g_mutex);
865         const int fd = ::accept (socket, address, address_len);
866         InvalidFDErrno fd_errno(fd);
867         StringSP description_sp(new String ("pid=%i: accept (socket=%i, ...) -> fd=%i", pid, socket, fd));
868         if (g_log_all_calls)
869             description_sp->log (get_logging_fd());
870         if (fd >= 0)
871             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
872         return fd;
873     }
874     else
875     {
876         return ::accept (socket, address, address_len);
877     }
878 }
879 
880 
881 //----------------------------------------------------------------------
882 // accept$NOCANCEL() interpose function
883 //----------------------------------------------------------------------
884 extern "C" int
accept$NOCANCEL$__interposed__(int socket,struct sockaddr * address,socklen_t * address_len)885 accept$NOCANCEL$__interposed__ (int socket, struct sockaddr *address, socklen_t *address_len)
886 {
887     const int pid = get_interposed_pid();
888     if (pid >= 0)
889     {
890         Locker locker (&g_mutex);
891         const int fd = ::accept$NOCANCEL (socket, address, address_len);
892         InvalidFDErrno fd_errno(fd);
893         StringSP description_sp(new String ("pid=%i: accept$NOCANCEL (socket=%i, ...) -> fd=%i", pid, socket, fd));
894         if (g_log_all_calls)
895             description_sp->log (get_logging_fd());
896         if (fd >= 0)
897             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
898         return fd;
899     }
900     else
901     {
902         return ::accept$NOCANCEL (socket, address, address_len);
903     }
904 }
905 
906 //----------------------------------------------------------------------
907 // dup() interpose function
908 //----------------------------------------------------------------------
909 extern "C" int
dup$__interposed__(int fd2)910 dup$__interposed__ (int fd2)
911 {
912     const int pid = get_interposed_pid();
913     if (pid >= 0)
914     {
915         Locker locker (&g_mutex);
916         const int fd = ::dup (fd2);
917         InvalidFDErrno fd_errno(fd);
918         StringSP description_sp(new String ("pid=%i: dup (fd2=%i) -> fd=%i", pid, fd2, fd));
919         if (g_log_all_calls)
920             description_sp->log (get_logging_fd());
921         if (fd >= 0)
922             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
923         return fd;
924     }
925     else
926     {
927         return ::dup (fd2);
928     }
929 }
930 
931 //----------------------------------------------------------------------
932 // dup2() interpose function
933 //----------------------------------------------------------------------
934 extern "C" int
dup2$__interposed__(int fd1,int fd2)935 dup2$__interposed__ (int fd1, int fd2)
936 {
937     const int pid = get_interposed_pid();
938     if (pid >= 0)
939     {
940         Locker locker (&g_mutex);
941         // If "fd2" is already opened, it will be closed during the
942         // dup2 call below, so we need to see if we have fd2 in our
943         // open map and treat it as a close(fd2)
944         FDEventMap::iterator pos = g_fd_event_map.find (fd2);
945         StringSP dup2_close_description_sp(new String ("pid=%i: dup2 (fd1=%i, fd2=%i) -> will close (fd=%i)", pid, fd1, fd2, fd2));
946         if (pos != g_fd_event_map.end() && pos->second.back()->IsCreateEvent())
947             save_backtrace (fd2, 0, dup2_close_description_sp, false);
948 
949         const int fd = ::dup2(fd1, fd2);
950         InvalidFDErrno fd_errno(fd);
951         StringSP description_sp(new String ("pid=%i: dup2 (fd1=%i, fd2=%i) -> fd=%i", pid, fd1, fd2, fd));
952         if (g_log_all_calls)
953             description_sp->log (get_logging_fd());
954 
955         if (fd >= 0)
956             save_backtrace (fd, fd_errno.get_errno(), description_sp, true);
957         return fd;
958     }
959     else
960     {
961         return ::dup2(fd1, fd2);
962     }
963 }
964 
965 //----------------------------------------------------------------------
966 // close() interpose function
967 //----------------------------------------------------------------------
968 extern "C" int
close$__interposed__(int fd)969 close$__interposed__ (int fd)
970 {
971     const int pid = get_interposed_pid();
972     if (pid >= 0)
973     {
974         Locker locker (&g_mutex);
975         const int err = close(fd);
976         NegativeErrorErrno err_errno(err);
977         StringSP description_sp (new String);
978         if (err == -1)
979             description_sp->printf("pid=%i: close (fd=%i) => %i errno = %i (%s))", pid, fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
980         else
981             description_sp->printf("pid=%i: close (fd=%i) => %i", pid, fd, err);
982         if (g_log_all_calls)
983             description_sp->log (get_logging_fd());
984 
985         if (err == 0)
986         {
987             if (fd >= 0)
988                 save_backtrace (fd, err, description_sp, false);
989         }
990         else if (err == -1)
991         {
992             if (err_errno.get_errno() == EBADF && fd != -1)
993             {
994                 backtrace_error ("close (fd=%d) resulted in EBADF:\n", fd);
995 
996                 FDEventMap::iterator pos = g_fd_event_map.find (fd);
997                 if (pos != g_fd_event_map.end())
998                 {
999                     log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed");
1000                 }
1001             }
1002         }
1003         return err;
1004     }
1005     else
1006     {
1007         return close (fd);
1008     }
1009 }
1010 
1011 //----------------------------------------------------------------------
1012 // close$NOCANCEL() interpose function
1013 //----------------------------------------------------------------------
1014 extern "C" int
close$NOCANCEL$__interposed__(int fd)1015 close$NOCANCEL$__interposed__ (int fd)
1016 {
1017     const int pid = get_interposed_pid();
1018     if (pid >= 0)
1019     {
1020         Locker locker (&g_mutex);
1021         const int err = close$NOCANCEL(fd);
1022         NegativeErrorErrno err_errno(err);
1023         StringSP description_sp (new String);
1024         if (err == -1)
1025             description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i errno = %i (%s))", pid, fd, err, err_errno.get_errno(), strerror(err_errno.get_errno()));
1026         else
1027             description_sp->printf("pid=%i: close$NOCANCEL (fd=%i) => %i", pid, fd, err);
1028         if (g_log_all_calls)
1029             description_sp->log (get_logging_fd());
1030 
1031         if (err == 0)
1032         {
1033             if (fd >= 0)
1034                 save_backtrace (fd, err, description_sp, false);
1035         }
1036         else if (err == -1)
1037         {
1038             if (err_errno.get_errno() == EBADF && fd != -1)
1039             {
1040                 backtrace_error ("close$NOCANCEL (fd=%d) resulted in EBADF\n:", fd);
1041 
1042                 FDEventMap::iterator pos = g_fd_event_map.find (fd);
1043                 if (pos != g_fd_event_map.end())
1044                 {
1045                     log (get_logging_fd(), pos->second.back().get(), "\nfd=%d was previously %s with this event:\n", fd, pos->second.back()->IsCreateEvent() ? "opened" : "closed");
1046                 }
1047             }
1048         }
1049         return err;
1050     }
1051     else
1052     {
1053         return close$NOCANCEL(fd);
1054     }
1055 }
1056 
1057 //----------------------------------------------------------------------
1058 // pipe() interpose function
1059 //----------------------------------------------------------------------
1060 extern "C" int
pipe$__interposed__(int fds[2])1061 pipe$__interposed__ (int fds[2])
1062 {
1063     const int pid = get_interposed_pid();
1064     if (pid >= 0)
1065     {
1066         Locker locker (&g_mutex);
1067         fds[0] = -1;
1068         fds[1] = -1;
1069         const int err = pipe (fds);
1070         const int saved_errno = errno;
1071         StringSP description_sp(new String ("pid=%i: pipe ({fd=%i, fd=%i}) -> err=%i", pid, fds[0], fds[1], err));
1072         if (g_log_all_calls)
1073             description_sp->log (get_logging_fd());
1074         if (fds[0] >= 0)
1075             save_backtrace (fds[0], saved_errno, description_sp, true);
1076         if (fds[1] >= 0)
1077             save_backtrace (fds[1], saved_errno, description_sp, true);
1078         errno = saved_errno;
1079         return err;
1080     }
1081     else
1082     {
1083         return pipe (fds);
1084     }
1085 }
1086 
1087 //----------------------------------------------------------------------
1088 // get_fd_history()
1089 //
1090 // This function allows runtime access to the file descriptor history.
1091 //
1092 // @param[in] log_fd
1093 //      The file descriptor to log to
1094 //
1095 // @param[in] fd
1096 //      The file descriptor whose history should be dumped
1097 //----------------------------------------------------------------------
1098 extern "C" void
get_fd_history(int log_fd,int fd)1099 get_fd_history (int log_fd, int fd)
1100 {
1101     // "create" below needs to be outside of the mutex locker scope
1102     if (log_fd >= 0)
1103     {
1104         bool got_lock = false;
1105         Locker locker (&g_mutex, got_lock);
1106         if (got_lock)
1107         {
1108             FDEventMap::iterator pos = g_fd_event_map.find (fd);
1109             log_to_fd (log_fd, "Dumping file descriptor history for fd=%i:\n", fd);
1110             if (pos != g_fd_event_map.end())
1111             {
1112                 FDEventArray &event_array = g_fd_event_map[fd];
1113                 const size_t num_events = event_array.size();
1114                 for (size_t i=0; i<num_events; ++i)
1115                     event_array[i]->Dump (log_fd);
1116             }
1117             else
1118             {
1119                 log_to_fd (log_fd, "error: no file descriptor events found for fd=%i\n", fd);
1120             }
1121         }
1122         else
1123         {
1124             log_to_fd (log_fd, "error: fd event mutex is locked...\n");
1125         }
1126     }
1127 }
1128 
1129 //----------------------------------------------------------------------
1130 // Interposing
1131 //----------------------------------------------------------------------
1132 // FD creation routines
1133 DYLD_INTERPOSE(accept$__interposed__, accept);
1134 DYLD_INTERPOSE(accept$NOCANCEL$__interposed__, accept$NOCANCEL);
1135 DYLD_INTERPOSE(dup$__interposed__, dup);
1136 DYLD_INTERPOSE(dup2$__interposed__, dup2);
1137 DYLD_INTERPOSE(kqueue$__interposed__, kqueue);
1138 DYLD_INTERPOSE(open$__interposed__, open);
1139 DYLD_INTERPOSE(open$NOCANCEL$__interposed__, open$NOCANCEL);
1140 DYLD_INTERPOSE(__open_extended$__interposed__, __open_extended);
1141 DYLD_INTERPOSE(pipe$__interposed__, pipe);
1142 DYLD_INTERPOSE(shm_open$__interposed__, shm_open);
1143 DYLD_INTERPOSE(socket$__interposed__, socket);
1144 DYLD_INTERPOSE(socketpair$__interposed__, socketpair);
1145 
1146 // FD deleting routines
1147 DYLD_INTERPOSE(close$__interposed__, close);
1148 DYLD_INTERPOSE(close$NOCANCEL$__interposed__, close$NOCANCEL);
1149 
1150 } // namespace fd_interposing
1151 
1152 
1153