From c5caaded086f169ad3f39e65ed52d20552b8360a Mon Sep 17 00:00:00 2001
From: Piotr Rak <piotr.rak@gmail.com>
Date: Sat, 22 Mar 2014 14:32:04 +0100
Subject: [PATCH] Avoid leaking file descriptors to child processes.

Intention of this patch is avoid having any file descriptor open
without O_CLOEXEC, unless necessary or in child process about to exec.
Otherwise it might cause them to leak if any other thread executes
(v)fork/exec() or posix_spawn. It otherwise would be impossible to
control.
If O_CLOEXEC is not supported, we use fcntl after open and try to
make this window as small as possible.

 o lldb_private::File opens files O_CLOEXEC by default where supported.
 o eOpenOptionInheritOnExecPosixFD File option for file to override that.
 o File::Duplicate uses F_DUPFD_CLOEXEC.
 o Add File::SetDescriptorInheritableAfterExec(bool) to change it.
 o Utility::PseudoTerminal and debugserver PseudoTerminal open terminals with O_CLOEXEC.
 o Retry if open/posix_openpt is interrupted by signal.
---
 include/lldb/Host/File.h                    |  67 +++++++-
 source/Host/common/File.cpp                 | 257 +++++++++++++++++++++++++++-
 source/Utility/PseudoTerminal.cpp           |  68 +++++++-
 tools/debugserver/source/PseudoTerminal.cpp | 106 +++++++++++-
 4 files changed, 483 insertions(+), 15 deletions(-)

diff --git a/include/lldb/Host/File.h b/include/lldb/Host/File.h
index 814d960..4bcf494 100644
--- a/include/lldb/Host/File.h
+++ b/include/lldb/Host/File.h
@@ -17,6 +17,10 @@
 
 #include "lldb/lldb-private.h"
 
+namespace lldb_utility {
+class PseudoTerminal;
+}
+
 namespace lldb_private {
 
 //----------------------------------------------------------------------
@@ -41,7 +45,11 @@ public:
         eOpenOptionNonBlocking          = (1u << 4),    // File reads
         eOpenOptionCanCreate            = (1u << 5),    // Create file if doesn't already exist
         eOpenOptionCanCreateNewOnly     = (1u << 6),    // Can create file only if it doesn't already exist
-        eOpenoptionDontFollowSymlinks   = (1u << 7)
+        eOpenoptionDontFollowSymlinks   = (1u << 7),
+        eOpenOptionInheritOnExecPosixFD = (1u << 8)     // Enable inheritance of file descriptor on exec(),
+                                                        // ie. as O_CLOEXEC open flag was _NOT_ specified for POSIX
+                                                        // systems. NOTE: Use of this STRONGLY DISCOURAGED
+                                                        // see SetDescriptorInheritableAfterExec() for more details
     };
     
     static mode_t
@@ -69,8 +77,16 @@ public:
     {
     }
 
+    //------------------------------------------------------------------
+    // NOTE: Resulting File descriptor of this file won't be inheritable
+    // to child process after exec().
+    //------------------------------------------------------------------
     File (const File &rhs);
     
+    //------------------------------------------------------------------
+    // NOTE: Resulting File descriptor of this file won't be inheritable
+    // to child process after exec().
+    //------------------------------------------------------------------
     File &
     operator= (const File &rhs);
     //------------------------------------------------------------------
@@ -90,6 +106,15 @@ public:
     ///     Options to use when opening (see File::Permissions)
     ///
     /// @see File::Open (const char *path, uint32_t options, uint32_t permissions)
+    ///
+    /// NOTE: On POSIX systems by default file will be opened as O_CLOEXEC
+    /// open flag was specified, meaning it will be not inherited by child process
+    /// after calling exec().
+    /// This behavior is exactly oposite to default POSIX behavior and
+    /// to override it you can specify eOpenOptionInheritOnExecPosixFD
+    /// or call SetInheritableAfterExec(true) afterwards.
+    /// If this operation cannot be done in atomic manner it shall be emulated
+    /// by setting FD_CLOEXEC flag after open().
     //------------------------------------------------------------------
     File (const char *path,
           uint32_t options,
@@ -102,6 +127,7 @@ public:
     /// path. If \a path is not NULL or empty, this function will call
     /// File::Open (const char *path, uint32_t options, uint32_t permissions).
     ///
+    ///
     /// @param[in] path
     ///     The FileSpec for this file.
     ///
@@ -216,9 +242,39 @@ public:
     Error
     Close ();
     
+    //------------------------------------------------------------------
+    // NOTE: Resulting file descriptor of this file won't be inheritable
+    // by child process after exec().
+    //------------------------------------------------------------------
     Error
     Duplicate (const File &rhs);
 
+    //------------------------------------------------------------------
+    /// Like Duplicate() but sets file descriptor as inheritable after
+    /// child process exec().
+    ///
+    /// NOTE: Use of this method is STRONGLY DISCOURAGED.
+    /// @sa SetDescriptorInheritableAfterExec()
+    //------------------------------------------------------------------
+    Error
+    DuplicateInheritableAfterExec (const File &rhs);
+
+    //------------------------------------------------------------------
+    /// Makes file descriptor inheritable after process for child process
+    /// after exec call on POSIX systems.
+    ///
+    /// NOTE: Its use with inheritable is STRONGLY DISCOURAGED, unless
+    /// ensured that all other threads are stopped, and all of the
+    /// signals are blocked.
+    /// This is generaly impossibe to achive beside case when child
+    /// process after fork() is just about to call exec().
+    ///
+    ///
+    /// @sa eOpenOptionInheritOnExecPosixFD
+    //------------------------------------------------------------------
+    Error
+    SetDescriptorInheritableAfterExec (bool inheritable);
+
     int
     GetDescriptor() const;
 
@@ -516,6 +572,15 @@ public:
     {
         m_options = options;
     }
+private:
+    static int
+    OpenAndSetCloseOnExec (const char*, int oflags);
+
+    static int
+    OpenAndSetCloseOnExec (const char*, int oflags, mode_t mode);
+
+    friend class lldb_utility::PseudoTerminal; // for OpenAndSetCloseOnExec()
+
 protected:
     
     
diff --git a/source/Host/common/File.cpp b/source/Host/common/File.cpp
index 500b03c..b40e154 100644
--- a/source/Host/common/File.cpp
+++ b/source/Host/common/File.cpp
@@ -27,6 +27,29 @@
 #include "lldb/Host/Config.h"
 #include "lldb/Host/FileSpec.h"
 
+#if !defined(LLDB_DISABLE_O_CLOEXEC) && !defined(O_CLOEXEC)
+#define LLDB_DISABLE_O_CLOEXEC 1
+
+#if !defined(_WIN32)
+// NOTE: For now we issue compile-time warning in that case, though, it will spam
+// future non-posix platforms builds and will require blacklisting them here.
+#warning "O_CLOEXEC not supported! This operation won't be atomic for open() in your build!"
+
+#endif // !defined(_WIN32)
+#endif // !defined(LLDB_DISABLE_O_CLOEXEC) && !defined(O_CLOEXEC)
+
+
+#if !defined(LLDB_DISABLE_DUPFD_CLOEXEC) && !defined(F_DUPFD_CLOEXEC)
+#define LLDB_DISABLE_DUPFD_CLOEXEC
+
+#if !defined(_WIN32)
+// NOTE: For now we issue compile-time warning in that case, though, it will spam
+// future non-posix platforms builds and will require blacklisting them here.
+#warning "F_DUPFD_CLOEXEC not supported! This operation won't be atomic for open() in your build!"
+
+#endif // !defined(_WIN32)
+#endif // !defined(LLDB_DISABLE_DUPFD_CLOEXEC) && !defined(F_DUPFD_CLOEXEC)
+
 using namespace lldb;
 using namespace lldb_private;
 
@@ -73,6 +96,93 @@ GetStreamOpenModeFromOptions (uint32_t options)
     return NULL;
 }
 
+#if !defined(_WIN32)
+
+static int
+DoDuplicateSetFD (int file_descriptor)
+{
+    int result = 0;
+    int duplicated = ::fcntl(file_descriptor, F_DUPFD);
+
+    if (duplicated != -1)
+        result = ::fcntl(duplicated, F_SETFD, FD_CLOEXEC);
+
+    if (result == -1)
+    {
+        // Stash errno so it is not changed even if close fails...
+        int saved_errno = errno;
+        ::close(duplicated);
+        duplicated = -1;
+        errno = saved_errno;
+    }
+
+    return duplicated;
+}
+#endif // !defined(_WIN32)
+
+static int
+DoDuplicateFDCloseOnExec (int file_descriptor)
+{
+#if defined(_WIN32)
+    int duplicated = ::_dup(file_descriptor);
+
+#elif !defined(LLDB_DISABLE_DUPFD_CLOEXEC)
+    int duplicated = ::fcntl (file_descriptor, F_DUPFD_CLOEXEC);
+
+    if (duplicated == -1 && errno == EINVAL)
+    {
+        // If F_DUPFD_CLOEXEC is not supported by running system fallback
+        // to non-atomic F_SETFD
+        duplicated = DoDuplicateSetFD (file_descriptor);
+    }
+
+#else // !defined(_WIN32) && defined(LLDB_DISABLE_DUPFD_CLOEXEC)
+    int duplicated = DoDuplicateSetFD(file_descriptor);
+#endif // end !defined(_WIN32) && !defined(F_DUPFD_CLOEXEC)
+
+    return duplicated;
+}
+
+static int DoOpenSetFD (const char* path, int oflags, mode_t mode)
+{
+    int fd = ::open (path, oflags, mode);
+
+    if (fd >= 0)
+    {
+#ifndef _WIN32
+        if (::fcntl (fd, F_SETFD, FD_CLOEXEC) == -1)
+        {
+            int saved_errno = errno;
+            ::close(fd);
+            errno = saved_errno;
+            fd = -1;
+        }
+#endif
+    }
+
+    return fd;
+}
+
+static int DoOpenSetFD (const char* path, int oflags)
+{
+    int fd = ::open (path, oflags);
+
+    if (fd >= 0)
+    {
+#ifndef _WIN32
+        if (::fcntl (fd, F_SETFD, FD_CLOEXEC) == -1)
+        {
+            int saved_errno = errno;
+            ::close(fd);
+            errno = saved_errno;
+            fd = -1;
+        }
+#endif
+    }
+
+    return fd;
+}
+
 int File::kInvalidDescriptor = -1;
 FILE * File::kInvalidStream = NULL;
 
@@ -172,11 +282,7 @@ File::GetStream ()
                 {
                     // We must duplicate the file descriptor if we don't own it because
                     // when you call fdopen, the stream will own the fd
-#ifdef _WIN32
-                    m_descriptor = ::_dup(GetDescriptor());
-#else
-                    m_descriptor = ::fcntl(GetDescriptor(), F_DUPFD);
-#endif
+                    m_descriptor = DoDuplicateFDCloseOnExec(GetDescriptor());
                     m_own_descriptor = true;
                 }
 
@@ -213,16 +319,52 @@ Error
 File::Duplicate (const File &rhs)
 {
     Error error;
+
+    // FIXME: This closes file even if later fails leaving File state somewhere
+    // inbetween, should this operation really be destructive in such manner???
     if (IsValid ())
         Close();
 
     if (rhs.DescriptorIsValid())
     {
-#ifdef _WIN32
+        m_descriptor = DoDuplicateFDCloseOnExec(rhs.GetDescriptor());
+
+        if (!DescriptorIsValid())
+            error.SetErrorToErrno();
+        else
+        {
+            m_options = rhs.m_options;
+            m_own_descriptor = true;
+        }
+    }
+    else
+    {
+        error.SetErrorString ("invalid file to duplicate");
+    }
+    return error;
+}
+
+Error
+File::DuplicateInheritableAfterExec(const File &rhs)
+{
+    Error error;
+
+    // FIXME: This closes file even if later fails leaving File state somewhere
+    // inbetween, should this operation really be destructive in such manner?
+    if (IsValid ())
+        Close();
+
+    if (rhs.DescriptorIsValid())
+    {
+#if defined(_WIN32)
+
         m_descriptor = ::_dup(rhs.GetDescriptor());
-#else
+
+#else // !defined(_WIN32)
+
         m_descriptor = ::fcntl(rhs.GetDescriptor(), F_DUPFD);
-#endif
+
+#endif // end !defined(_WIN32)
         if (!DescriptorIsValid())
             error.SetErrorToErrno();
         else
@@ -239,6 +381,28 @@ File::Duplicate (const File &rhs)
 }
 
 Error
+File::SetDescriptorInheritableAfterExec (bool inheritable)
+{
+    Error error;
+
+
+    if (DescriptorIsValid())
+    {
+#ifndef _WIN32
+        int set_fd = inheritable? 0 : FD_CLOEXEC;
+
+        if (::fcntl(GetDescriptor(), F_SETFD, set_fd) == -1)
+            error.SetErrorToErrno();
+#endif
+    }
+    else
+    {
+        error.SetErrorString("invalid file descriptor");
+    }
+    return error;
+}
+
+Error
 File::Open (const char *path, uint32_t options, uint32_t permissions)
 {
     Error error;
@@ -248,6 +412,8 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
     int oflag = 0;
     const bool read = options & eOpenOptionRead;
     const bool write = options & eOpenOptionWrite;
+    const bool inherit_on_exec = options & eOpenOptionInheritOnExecPosixFD;
+
     if (write)
     {
         if (read)
@@ -280,10 +446,19 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
 #ifndef _WIN32
     if (options & eOpenOptionNonBlocking)
         oflag |= O_NONBLOCK;
+
 #else
     oflag |= O_BINARY;
 #endif
 
+// FIXME: we should probably be able enable this one even if build host doesn't
+// support O_CLOEXEC. Unfortunely it is really hard as it's value will differ
+// through platforms or even might differ between system versions.
+#if !defined(LLDB_DISABLE_O_CLOEXEC)
+    if (inherit_on_exec)
+        oflag |= O_CLOEXEC;
+#endif // !defined(LLDB_DISABLE_O_CLOEXEC)
+
     mode_t mode = 0;
     if (oflag & O_CREAT)
     {
@@ -300,7 +475,22 @@ File::Open (const char *path, uint32_t options, uint32_t permissions)
 
     do
     {
+
+#if !defined(LLDB_DISABLE_O_CLOEXEC)
         m_descriptor = ::open(path, oflag, mode);
+
+        // If system we are running doesn't support O_CLOEXEC, lets emulate it.
+        if (!inherit_on_exec &&
+            m_descriptor < 0 &&
+            errno == EINVAL)
+        {
+            oflag &= ~static_cast<int>(O_CLOEXEC);
+            m_descriptor = DoOpenSetFD (path, oflag, mode);
+        }
+#elif !defined(_WIN32)
+        m_descriptor = DoOpenSetFD(path, oflag, mode);
+#endif // !defined(LLDB_DISABLE_O_CLOEXEC)
+
     } while (m_descriptor < 0 && errno == EINTR);
 
     if (!DescriptorIsValid())
@@ -853,9 +1043,53 @@ File::PrintfVarArg (const char *format, va_list args)
     return result;
 }
 
+int
+File::OpenAndSetCloseOnExec(const char *path, int oflag)
+{
+    int fd = -1;
+    do
+    {
+#if !defined(LLDB_DISABLE_O_CLOEXEC)
+        int oflag_ocloexec = oflag | O_CLOEXEC;
+        fd = ::open(path, oflag_ocloexec);
+
+        if (fd < 0 && errno == EINVAL)
+            fd = DoOpenSetFD(path, oflag);
+#else
+        fd = DoOpenSetFD(path, oflag);
+#endif
+    }
+    while (fd < 0 && errno == EINTR);
+
+    return fd;
+}
+
+int
+File::OpenAndSetCloseOnExec(const char *path, int oflag, mode_t mode)
+{
+    int fd = -1;
+    do
+    {
+#if !defined(LLDB_DISABLE_O_CLOEXEC)
+        int oflag_ocloexec = oflag | O_CLOEXEC;
+        fd = ::open(path, oflag_ocloexec, mode);
+
+        if (fd < 0 && errno == EINVAL)
+            fd = DoOpenSetFD(path, oflag, mode);
+#else
+        fd = DoOpenSetFD(path, oflag, mode);
+#endif
+    }
+    while (fd < 0 && errno == EINTR);
+
+    return fd;
+}
+
 mode_t
 File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
 {
+    bool inherit_on_exec = open_options & eOpenOptionInheritOnExecPosixFD;
+
     mode_t mode = 0;
     if (open_options & eOpenOptionRead && open_options & eOpenOptionWrite)
         mode |= O_RDWR;
@@ -871,6 +1105,13 @@ File::ConvertOpenOptionsForPOSIXOpen (uint32_t open_options)
     if (open_options & eOpenOptionNonBlocking)
         mode |= O_NONBLOCK;
 
+    if (!inherit_on_exec)
+    {
+#if !defined(LLDB_DISABLE_O_CLOEXEC)
+        mode |= O_CLOEXEC;
+#endif
+    }
+
     if (open_options & eOpenOptionCanCreateNewOnly)
         mode |= O_CREAT | O_EXCL;
     else if (open_options & eOpenOptionCanCreate)
diff --git a/source/Utility/PseudoTerminal.cpp b/source/Utility/PseudoTerminal.cpp
index 98d581d..1df4b3c 100644
--- a/source/Utility/PseudoTerminal.cpp
+++ b/source/Utility/PseudoTerminal.cpp
@@ -8,6 +8,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Utility/PseudoTerminal.h"
+#include "lldb/Host/File.h"
 
 #include <errno.h>
 #include <stdlib.h>
@@ -17,11 +18,21 @@
 #include <sys/ioctl.h>
 #endif
 
+#if !defined(LLDB_DISABLE_O_CLOEXEC) && !defined(O_CLOEXEC)
+#define LLDB_DISABLE_O_CLOEXEC 1
+
+#if !defined(_WIN32)
+// NOTE: For now we issue compile-time warning in that case, though, it will spam
+// future non-posix platforms builds and will require blacklisting them here.
+#warning "O_CLOEXEC not supported! This operation won't be atomic for open() in your build!"
+
+#endif // !defined(_WIN32)
+#endif // !defined(LLDB_DISABLE_O_CLOEXEC) && !defined(O_CLOEXEC)
+
 #ifdef _WIN32
 #include "lldb/Host/windows/win32.h"
 // empty functions
-int posix_openpt(int flag) { return 0; }
-
+static int DoPosixOpenPTCloseOnExec() { return 0; }
 int strerror_r(int errnum, char *buf, size_t buflen) { return 0; }
 
 int unlockpt(int fd) { return 0; }
@@ -30,10 +41,58 @@ char *ptsname(int fd) { return 0; }
 
 pid_t fork(void) { return 0; }
 pid_t setsid(void) { return 0; }
+#else
+
+static int
+DoPosixOpenPTCloseOnExec(int oflag)
+{
+    int fd = -1;
+    do
+    {
+#ifdef LLDB_DISABLE_O_CLOEXEC
+        int oflag_cloexec = oflag | O_CLOEXEC;
+
+        fd = ::posix_openpt(oflag_cloexec);
+
+        // If O_CLOEXEC is not supported try to emulate it by /dev/ptmx
+        if (fd < 0 && errno == EINVAL)
+            fd = ::open("/dev/ptmx", oflag_cloexec);
+
+        if (fd < 0)
+        {
+            switch (errno) {
+            case EINTR:     continue;  // retry
+            case EINVAL:    break;     // try emulate
+            default:        return fd; // return
+            }
+        }
+#endif
+        // Emulate O_CLOEXEC by fcntl
+        if (fd < 0)
+        {
+            fd = ::posix_openpt(oflag);
+            if (fd >= 0)
+            {
+                int ret = ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+                if (ret == -1)
+                {
+                    int saved_errno = errno;
+                    ::close(fd);
+                    errno = saved_errno;
+                    fd = -1;
+                }
+            }
+        }
+    }
+    while (fd < 0 && errno == EINTR);
+
+    return fd;
+}
 #endif
 
 using namespace lldb_utility;
 
+
 //----------------------------------------------------------------------
 // PseudoTerminal constructor
 //----------------------------------------------------------------------
@@ -104,7 +163,7 @@ PseudoTerminal::OpenFirstAvailableMaster (int oflag, char *error_str, size_t err
         error_str[0] = '\0';
 
     // Open the master side of a pseudo terminal
-    m_master_fd = ::posix_openpt (oflag);
+    m_master_fd = DoPosixOpenPTCloseOnExec (oflag);
     if (m_master_fd < 0)
     {
         if (error_str)
@@ -158,7 +217,8 @@ PseudoTerminal::OpenSlave (int oflag, char *error_str, size_t error_len)
     if (slave_name == NULL)
         return false;
 
-    m_slave_fd = ::open (slave_name, oflag);
+    using lldb_private::File;
+    m_slave_fd = File::OpenAndSetCloseOnExec (slave_name, oflag);
 
     if (m_slave_fd < 0)
     {
diff --git a/tools/debugserver/source/PseudoTerminal.cpp b/tools/debugserver/source/PseudoTerminal.cpp
index f1b505c..77a2d90 100644
--- a/tools/debugserver/source/PseudoTerminal.cpp
+++ b/tools/debugserver/source/PseudoTerminal.cpp
@@ -16,6 +16,107 @@
 #include <sys/ioctl.h>
 #include <unistd.h>
 
+#if !defined(LLDB_DISABLE_O_CLOEXEC) && !defined(O_CLOEXEC)
+#define LLDB_DISABLE_O_CLOEXEC 1
+
+#if !defined(_WIN32)
+// NOTE: For now we issue compile-time warning in that case, though, it will spam
+// future non-posix platforms builds and will require blacklisting them here.
+#warning "O_CLOEXEC not supported! This operation won't be atomic for open() in your build!"
+
+#endif // !defined(_WIN32)
+#endif // !defined(LLDB_DISABLE_O_CLOEXEC) && !defined(O_CLOEXEC)
+
+// Copied from source/Utility/PseudoTerminal.cpp
+// Please try to keep in sync!
+static int
+DoPosixOpenPTCloseOnExec(int oflag)
+{
+    int fd = -1;
+    do
+    {
+#if !defined(LLDB_DISABLE_O_CLOEXEC)
+        int oflag_cloexec = oflag | O_CLOEXEC;
+
+        fd = ::posix_openpt(oflag_cloexec);
+
+        // If O_CLOEXEC is not supported try to emulate it by /dev/ptmx
+        if (fd < 0 && errno == EINVAL)
+            fd = ::open("/dev/ptmx", oflag_cloexec);
+
+        if (fd < 0)
+        {
+            switch (errno) {
+            case EINTR:     continue;  // retry
+            case EINVAL:    break;     // try emulate
+            default:        return fd; // return
+            }
+        }
+#endif
+        // Emulate O_CLOEXEC by fcntl
+        if (fd < 0)
+        {
+            fd = ::posix_openpt(oflag);
+            if (fd >= 0)
+            {
+                int ret = ::fcntl(fd, F_SETFD, FD_CLOEXEC);
+                if (ret == -1)
+                {
+                    int saved_errno = errno;
+                    ::close(fd);
+                    errno = saved_errno;
+                    fd = -1;
+                }
+            }
+        }
+    }
+    while (fd < 0 && errno == EINTR);
+
+    return fd;
+}
+
+// Copied from Host/File.cpp please try to keep in sync!
+static int DoOpenSetFD (const char* path, int oflags)
+{
+    int fd = ::open (path, oflags);
+
+    if (fd >= 0)
+    {
+#ifndef _WIN32
+        if (::fcntl (fd, F_SETFD, FD_CLOEXEC) == -1)
+        {
+            int saved_errno = errno;
+            ::close(fd);
+            errno = saved_errno;
+            fd = -1;
+        }
+#endif
+    }
+
+    return fd;
+}
+
+static int
+OpenAndSetCloseOnExec(const char *path, int oflag)
+{
+    int fd = -1;
+    do
+    {
+#if !defined(LLDB_DISABLE_O_CLOEXEC)
+        int oflag_ocloexec = oflag | O_CLOEXEC;
+        fd = ::open(path, oflag_ocloexec);
+
+        if (fd < 0 && errno == EINVAL)
+            fd = DoOpenSetFD(path, oflag);
+#else
+        fd = DoOpenSetFD(path, oflag);
+#endif
+    }
+    while (fd < 0 && errno == EINTR);
+
+    return fd;
+}
+
 //----------------------------------------------------------------------
 // PseudoTerminal constructor
 //----------------------------------------------------------------------
@@ -79,7 +180,7 @@ PseudoTerminal::Error
 PseudoTerminal::OpenFirstAvailableMaster(int oflag)
 {
     // Open the master side of a pseudo terminal
-    m_master_fd = ::posix_openpt (oflag);
+    m_master_fd = DoPosixOpenPTCloseOnExec (oflag);
     if (m_master_fd < 0)
     {
         return err_posix_openpt_failed;
@@ -123,7 +224,7 @@ PseudoTerminal::OpenSlave(int oflag)
     if (slave_name == NULL)
         return err_ptsname_failed;
 
-    m_slave_fd = ::open (slave_name, oflag);
+    m_slave_fd = OpenAndSetCloseOnExec (slave_name, oflag);
 
     if (m_slave_fd < 0)
         return err_open_slave_failed;
@@ -179,6 +280,7 @@ pid_t
 PseudoTerminal::Fork(PseudoTerminal::Error& error)
 {
     pid_t pid = invalid_pid;
+
     error = OpenFirstAvailableMaster (O_RDWR|O_NOCTTY);
 
     if (error == 0)
-- 
1.9.0

