IPC::Connection receive ports should be guarded
authorandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Feb 2017 22:52:02 +0000 (22:52 +0000)
committerandersca@apple.com <andersca@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Wed, 1 Feb 2017 22:52:02 +0000 (22:52 +0000)
https://bugs.webkit.org/show_bug.cgi?id=167704

Reviewed by Tim Horton.

Guarding receive rights will make sure that they won't be closed accidentally. They are created
with a context pointer and can only be unguarded or destructed with the same context pointer.

* Platform/IPC/mac/ConnectionMac.mm:
(IPC::Connection::platformInvalidate):
Use mach_port_destruct and pass the connection pointer as the context.

(IPC::Connection::platformInitialize):
Guard the server port with the connection pointer as the context.

(IPC::Connection::open):
Use mach_port_construct to create the port which lets us avoid a call to mach_port_set_attributes and setMachPortQueueLength.
Make the port guarded and use the connection pointer as the context.

(IPC::createReceiveSource):
Get rid of this and just duplicate the five lines of code in two places. For the receive port we want to use mach_port_destruct
in our cancel handler.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@211535 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Source/WebKit2/ChangeLog
Source/WebKit2/Platform/IPC/mac/ConnectionMac.mm

index 4de55c1..18875b7 100644 (file)
@@ -1,3 +1,28 @@
+2017-02-01  Anders Carlsson  <andersca@apple.com>
+
+        IPC::Connection receive ports should be guarded
+        https://bugs.webkit.org/show_bug.cgi?id=167704
+
+        Reviewed by Tim Horton.
+
+        Guarding receive rights will make sure that they won't be closed accidentally. They are created
+        with a context pointer and can only be unguarded or destructed with the same context pointer.
+
+        * Platform/IPC/mac/ConnectionMac.mm:
+        (IPC::Connection::platformInvalidate):
+        Use mach_port_destruct and pass the connection pointer as the context.
+
+        (IPC::Connection::platformInitialize):
+        Guard the server port with the connection pointer as the context.
+
+        (IPC::Connection::open):
+        Use mach_port_construct to create the port which lets us avoid a call to mach_port_set_attributes and setMachPortQueueLength.
+        Make the port guarded and use the connection pointer as the context.
+
+        (IPC::createReceiveSource):
+        Get rid of this and just duplicate the five lines of code in two places. For the receive port we want to use mach_port_destruct
+        in our cancel handler.
+
 2017-02-01  Andreas Kling  <akling@apple.com>
 
         Implement the alwaysRunsAtBackgroundPriority WK2 setting using thread QoS.
index 72b3aa8..9e14355 100644 (file)
@@ -120,7 +120,7 @@ void Connection::platformInvalidate()
         }
 
         if (m_receivePort) {
-            mach_port_mod_refs(mach_task_self(), m_receivePort, MACH_PORT_RIGHT_RECEIVE, -1);
+            mach_port_destruct(mach_task_self(), m_receivePort, 0, reinterpret_cast<mach_port_context_t>(this));
             m_receivePort = MACH_PORT_NULL;
         }
 
@@ -170,6 +170,8 @@ void Connection::platformInitialize(Identifier identifier)
     if (m_isServer) {
         m_receivePort = identifier.port;
         m_sendPort = MACH_PORT_NULL;
+
+        mach_port_guard(mach_task_self(), m_receivePort, reinterpret_cast<mach_port_context_t>(this), true);
     } else {
         m_receivePort = MACH_PORT_NULL;
         m_sendPort = identifier.port;
@@ -181,19 +183,6 @@ void Connection::platformInitialize(Identifier identifier)
     m_xpcConnection = identifier.xpcConnection;
 }
 
-template<typename Function>
-static dispatch_source_t createReceiveSource(mach_port_t receivePort, WorkQueue& workQueue, Function&& function)
-{
-    dispatch_source_t source = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, receivePort, 0, workQueue.dispatchQueue());
-    dispatch_source_set_event_handler(source, function);
-
-    dispatch_source_set_cancel_handler(source, ^{
-        mach_port_mod_refs(mach_task_self(), receivePort, MACH_PORT_RIGHT_RECEIVE, -1);
-    });
-
-    return source;
-}
-
 bool Connection::open()
 {
     if (m_isServer) {
@@ -205,37 +194,45 @@ bool Connection::open()
         ASSERT(m_sendPort);
 
         // Create the receive port.
-        mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &m_receivePort);
+        uint32_t flags = MPO_CONTEXT_AS_GUARD | MPO_QLIMIT |  MPO_STRICT | MPO_INSERT_SEND_RIGHT;
 
 #if PLATFORM(MAC)
-        mach_port_set_attributes(mach_task_self(), m_receivePort, MACH_PORT_DENAP_RECEIVER, (mach_port_info_t)0, 0);
+        flags |= MPO_DENAP_RECEIVER;
 #endif
 
+        mach_port_options_t portOptions;
+        portOptions.flags = flags;
+        portOptions.mpl.mpl_qlimit = MACH_PORT_QLIMIT_LARGE;
+        mach_port_construct(mach_task_self(), &portOptions, reinterpret_cast<mach_port_context_t>(this), &m_receivePort);
+
         m_isConnected = true;
         
-        // Send the initialize message, which contains a send right for the server to use.
         auto encoder = std::make_unique<Encoder>("IPC", "InitializeConnection", 0);
-        encoder->encode(MachPort(m_receivePort, MACH_MSG_TYPE_MAKE_SEND));
+        encoder->encode(MachPort(m_receivePort, MACH_MSG_TYPE_MOVE_SEND));
 
         initializeSendSource();
 
         sendMessage(WTFMove(encoder), { });
     }
 
-    // Change the message queue length for the receive port.
-    setMachPortQueueLength(m_receivePort, MACH_PORT_QLIMIT_LARGE);
-
-    // Register the data available handler.
     RefPtr<Connection> connection(this);
-    m_receiveSource = createReceiveSource(m_receivePort, m_connectionQueue, [connection] {
+    m_receiveSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, m_receivePort, 0, m_connectionQueue->dispatchQueue());
+    dispatch_source_set_event_handler(m_receiveSource, [connection] {
         connection->receiveSourceEventHandler();
     });
+    dispatch_source_set_cancel_handler(m_receiveSource, [connection, receivePort = m_receivePort] {
+        mach_port_destruct(mach_task_self(), receivePort, 0, reinterpret_cast<mach_port_context_t>(connection.get()));
+    });
 
 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED <= 101000
     if (m_exceptionPort) {
-        m_exceptionPortDataAvailableSource = createReceiveSource(m_exceptionPort, m_connectionQueue, [connection] {
+        m_exceptionPortDataAvailableSource = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_RECV, m_exceptionPort, 0, m_connectionQueue.dispatchQueue());
+        dispatch_source_set_event_handler(source, [connection] {
             connection->exceptionSourceEventHandler();
         });
+        dispatch_source_set_cancel_handler(source, [connection, exceptionPort = connection->m_exceptionPort] {
+            mach_port_mod_refs(mach_task_self(), exceptionPort, MACH_PORT_RIGHT_RECEIVE, -1);
+        });
 
         auto encoder = std::make_unique<Encoder>("IPC", "SetExceptionPort", 0);
         encoder->encode(MachPort(m_exceptionPort, MACH_MSG_TYPE_MAKE_SEND));