Repository: mesos
Updated Branches:
  refs/heads/1.0.x c76a3d355 -> d6132c58c


Fixed potential FD double close in the libevent socket.

`evbuffer_add_file` will take ownership of the file descriptor passed
into it.  Normally, this file descriptor is owned by the `FileEncoder`
in the libprocess's `SocketManager`.  Since there are two owners, one
of the owners may close the file descriptor when it has been re-used.

In this case, when multiple threads access the master's web UI at once
with SSL enabled, the master may CHECK-fail due to a bad (closed)
file descriptor.

Review: https://reviews.apache.org/r/51509/


Project: http://git-wip-us.apache.org/repos/asf/mesos/repo
Commit: http://git-wip-us.apache.org/repos/asf/mesos/commit/4c5bdd68
Tree: http://git-wip-us.apache.org/repos/asf/mesos/tree/4c5bdd68
Diff: http://git-wip-us.apache.org/repos/asf/mesos/diff/4c5bdd68

Branch: refs/heads/1.0.x
Commit: 4c5bdd683ef35880f9de2884657f2b7aead8abb6
Parents: c76a3d3
Author: Joseph Wu <jos...@mesosphere.io>
Authored: Mon Sep 12 12:40:09 2016 -0700
Committer: Joseph Wu <josep...@apache.org>
Committed: Thu Sep 15 09:58:17 2016 -0700

----------------------------------------------------------------------
 3rdparty/libprocess/src/libevent_ssl_socket.cpp | 38 ++++++++++++++++++--
 1 file changed, 36 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mesos/blob/4c5bdd68/3rdparty/libprocess/src/libevent_ssl_socket.cpp
----------------------------------------------------------------------
diff --git a/3rdparty/libprocess/src/libevent_ssl_socket.cpp 
b/3rdparty/libprocess/src/libevent_ssl_socket.cpp
index 57a63f6..93a33e5 100644
--- a/3rdparty/libprocess/src/libevent_ssl_socket.cpp
+++ b/3rdparty/libprocess/src/libevent_ssl_socket.cpp
@@ -741,6 +741,36 @@ Future<size_t> LibeventSSLSocketImpl::sendfile(
     std::swap(request, send_request);
   }
 
+  // Duplicate the file descriptor because Libevent will take ownership
+  // and control the lifecycle separately.
+  //
+  // TODO(josephw): We can avoid duplicating the file descriptor in
+  // future versions of Libevent. In Libevent versions 2.1.2 and later,
+  // we may use `evbuffer_file_segment_new` and `evbuffer_add_file_segment`
+  // instead of `evbuffer_add_file`.
+  int owned_fd = dup(fd);
+  if (fd == -1) {
+    return Failure(ErrnoError("Failed to duplicate file descriptor"));
+  }
+
+  // Set the close-on-exec flag.
+  Try<Nothing> cloexec = os::cloexec(owned_fd);
+  if (cloexec.isError()) {
+    os::close(owned_fd);
+    return Failure(
+        "Failed to set close-on-exec on duplicated file descriptor: " +
+        cloexec.error());
+  }
+
+  // Make the file descriptor non-blocking.
+  Try<Nothing> nonblock = os::nonblock(owned_fd);
+  if (nonblock.isError()) {
+    os::close(owned_fd);
+    return Failure(
+        "Failed to make duplicated file descriptor non-blocking: " +
+        nonblock.error());
+  }
+
   // Extend the life-time of 'this' through the execution of the
   // lambda in the event loop. Note: The 'self' needs to be explicitly
   // captured because we're not using it in the body of the lambda. We
@@ -749,7 +779,7 @@ Future<size_t> LibeventSSLSocketImpl::sendfile(
   auto self = shared(this);
 
   run_in_event_loop(
-      [self, fd, offset, size]() {
+      [self, owned_fd, offset, size]() {
         CHECK(__in_event_loop__);
         CHECK(self);
 
@@ -765,12 +795,16 @@ Future<size_t> LibeventSSLSocketImpl::sendfile(
         }
 
         if (write) {
+          // NOTE: `evbuffer_add_file` will take ownership of the file
+          // descriptor and close it after it has finished reading it.
           int result = evbuffer_add_file(
               bufferevent_get_output(self->bev),
-              fd,
+              owned_fd,
               offset,
               size);
           CHECK_EQ(0, result);
+        } else {
+          os::close(owned_fd);
         }
       },
       DISALLOW_SHORT_CIRCUIT);

Reply via email to