Bug 1126720: Support random postfix for Bluetooth daemon socket name (under bluetooth2/), r=btian
authorThomas Zimmermann <tdz@users.sourceforge.net>
Thu, 12 Feb 2015 10:12:07 +0100
changeset 256088 2cdf7ddcfc457694821f3c00af31a5969f6c0727
parent 256087 39ca2a6127a82dbb1f349805b5a7b45d4b0dcc2d
child 256089 562b55f88c647ff8b9e1dd7df6b4bd2465352a00
push id4610
push userjlund@mozilla.com
push dateMon, 30 Mar 2015 18:32:55 +0000
treeherdermozilla-beta@4df54044d9ef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbtian
bugs1126720, 1119746
milestone38.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1126720: Support random postfix for Bluetooth daemon socket name (under bluetooth2/), r=btian This patch adds support for a random postfix for bluetoothd's socket name. The postfix is re-generated for every instance of the daemon. This prevents name collisions between mutliple sessions and malicious programs from taking over the connection easily. This patch is based on bug 1119746, patch [05].
dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.cpp
@@ -2,26 +2,28 @@
 /* vim: set ts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this file,
  * You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "BluetoothDaemonInterface.h"
 #include <cutils/properties.h>
 #include <fcntl.h>
+#include <stdlib.h>
 #include "BluetoothDaemonA2dpInterface.h"
 #include "BluetoothDaemonAvrcpInterface.h"
 #include "BluetoothDaemonHandsfreeInterface.h"
 #include "BluetoothDaemonHelpers.h"
 #include "BluetoothDaemonSetupInterface.h"
 #include "BluetoothDaemonSocketInterface.h"
 #include "BluetoothInterfaceHelpers.h"
 #include "mozilla/ipc/ListenSocket.h"
 #include "mozilla/ipc/UnixSocketConnector.h"
 #include "mozilla/unused.h"
+#include "prrng.h"
 
 using namespace mozilla::ipc;
 
 BEGIN_BLUETOOTH_NAMESPACE
 
 //
 // Protocol initialization and setup
 //
@@ -1899,20 +1901,23 @@ private:
 
 void
 BluetoothDaemonInterface::OnConnectSuccess(enum Channel aChannel)
 {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!mResultHandlerQ.IsEmpty());
 
   switch (aChannel) {
-    case LISTEN_SOCKET:
-      // Init, step 2: Start Bluetooth daemon */
-      if (NS_WARN_IF(property_set("ctl.start", "bluetoothd") < 0)) {
-        OnConnectError(CMD_CHANNEL);
+    case LISTEN_SOCKET: {
+        // Init, step 2: Start Bluetooth daemon */
+        nsCString value("bluetoothd:-a ");
+        value.Append(mListenSocketName);
+        if (NS_WARN_IF(property_set("ctl.start", value.get()) < 0)) {
+          OnConnectError(CMD_CHANNEL);
+        }
       }
       break;
     case CMD_CHANNEL:
       // Init, step 3: Listen for notification channel...
       if (!mNtfChannel) {
         mNtfChannel = new BluetoothDaemonChannel(this, NTF_CHANNEL, mProtocol);
       } else if (
         NS_WARN_IF(mNtfChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
@@ -2062,16 +2067,56 @@ public:
     // Unused.
     MOZ_CRASH("This should never be called!");
   }
 
 private:
   nsCString mSocketName;
 };
 
+nsresult
+BluetoothDaemonInterface::CreateRandomAddressString(
+  const nsACString& aPrefix, unsigned long aPostfixLength,
+  nsACString& aAddress)
+{
+  static const char sHexChar[16] = {
+    [0x0] = '0', [0x1] = '1', [0x2] = '2', [0x3] = '3',
+    [0x4] = '4', [0x5] = '5', [0x6] = '6', [0x7] = '7',
+    [0x8] = '8', [0x9] = '9', [0xa] = 'a', [0xb] = 'b',
+    [0xc] = 'c', [0xd] = 'd', [0xe] = 'e', [0xf] = 'f'
+  };
+
+  unsigned short seed[3];
+
+  if (NS_WARN_IF(!PR_GetRandomNoise(seed, sizeof(seed)))) {
+    return NS_ERROR_NOT_IMPLEMENTED;
+  }
+
+  aAddress = aPrefix;
+  aAddress.Append('-');
+
+  while (aPostfixLength) {
+
+    // Android doesn't provide rand_r, so we use nrand48 here,
+    // even though it's deprecated.
+    long value = nrand48(seed);
+
+    size_t bits = sizeof(value) * CHAR_BIT;
+
+    while ((bits > 4) && aPostfixLength) {
+      aAddress.Append(sHexChar[value&0xf]);
+      bits -= 4;
+      value >>= 4;
+      --aPostfixLength;
+    }
+  }
+
+  return NS_OK;
+}
+
 /*
  * The init procedure consists of several steps.
  *
  *  (1) Start listening for the command channel's socket connection: We
  *      do this before anything else, so that we don't miss connection
  *      requests from the Bluetooth daemon. This step will create a
  *      listen socket.
  *
@@ -2098,19 +2143,21 @@ private:
  * caller.
  */
 void
 BluetoothDaemonInterface::Init(
   BluetoothNotificationHandler* aNotificationHandler,
   BluetoothResultHandler* aRes)
 {
   static const char BASE_SOCKET_NAME[] = "bluetoothd";
+  static unsigned long POSTFIX_LENGTH = 16;
 
-  // If we could not cleanup before and an old instance of the
-  // daemon is still running, we kill it here.
+  // If we could not cleanup properly before and an old
+  // instance of the daemon is still running, we kill it
+  // here.
   unused << NS_WARN_IF(property_set("ctl.stop", "bluetoothd"));
 
   sNotificationHandler = aNotificationHandler;
 
   mResultHandlerQ.AppendElement(aRes);
 
   if (!mProtocol) {
     mProtocol = new BluetoothDaemonProtocol();
@@ -2125,19 +2172,31 @@ BluetoothDaemonInterface::Init(
   if (!mCmdChannel) {
     mCmdChannel = new BluetoothDaemonChannel(this, CMD_CHANNEL, mProtocol);
   } else if (
     NS_WARN_IF(mCmdChannel->GetConnectionStatus() == SOCKET_CONNECTED)) {
     // Command channel should not be open; let's close it.
     mCmdChannel->CloseSocket();
   }
 
+  // The listen socket's name is generated with a random postfix. This
+  // avoids naming collisions if we still have a listen socket from a
+  // previously failed cleanup. It also makes it hard for malicious
+  // external programs to capture the socket name or connect before
+  // the daemon can do so. If no random postfix can be generated, we
+  // simply use the base name as-is.
+  nsresult rv = CreateRandomAddressString(NS_LITERAL_CSTRING(BASE_SOCKET_NAME),
+                                          POSTFIX_LENGTH,
+                                          mListenSocketName);
+  if (NS_FAILED(rv)) {
+    mListenSocketName = BASE_SOCKET_NAME;
+  }
+
   bool success = mListenSocket->Listen(
-    new BluetoothDaemonSocketConnector(NS_LITERAL_CSTRING(BASE_SOCKET_NAME)),
-    mCmdChannel);
+    new BluetoothDaemonSocketConnector(mListenSocketName), mCmdChannel);
   if (!success) {
     OnConnectError(CMD_CHANNEL);
     return;
   }
 
   // The protocol implementation needs a command channel for
   // sending commands to the daemon. We set it here, because
   // this is the earliest time when it's available.
--- a/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
+++ b/dom/bluetooth2/bluedroid/BluetoothDaemonInterface.h
@@ -103,32 +103,37 @@ public:
   BluetoothSocketInterface* GetBluetoothSocketInterface() MOZ_OVERRIDE;
   BluetoothHandsfreeInterface* GetBluetoothHandsfreeInterface() MOZ_OVERRIDE;
   BluetoothA2dpInterface* GetBluetoothA2dpInterface() MOZ_OVERRIDE;
   BluetoothAvrcpInterface* GetBluetoothAvrcpInterface() MOZ_OVERRIDE;
   BluetoothGattInterface* GetBluetoothGattInterface() MOZ_OVERRIDE;
 
 protected:
   enum Channel {
+    LISTEN_SOCKET,
     CMD_CHANNEL,
     NTF_CHANNEL
   };
 
-  BluetoothDaemonInterface(BluetoothDaemonChannel* aCmdChannel,
-                           BluetoothDaemonChannel* aNtfChannel,
-                           BluetoothDaemonProtocol* aProtocol);
+  BluetoothDaemonInterface();
   ~BluetoothDaemonInterface();
 
   void OnConnectSuccess(enum Channel aChannel);
   void OnConnectError(enum Channel aChannel);
   void OnDisconnect(enum Channel aChannel);
 
+  nsresult CreateRandomAddressString(const nsACString& aPrefix,
+                                     unsigned long aPostfixLength,
+                                     nsACString& aAddress);
+
 private:
   void DispatchError(BluetoothResultHandler* aRes, BluetoothStatus aStatus);
 
+  nsCString mListenSocketName;
+  nsRefPtr<BluetoothDaemonListenSocket> mListenSocket;
   nsRefPtr<BluetoothDaemonChannel> mCmdChannel;
   nsRefPtr<BluetoothDaemonChannel> mNtfChannel;
   nsAutoPtr<BluetoothDaemonProtocol> mProtocol;
 
   nsTArray<nsRefPtr<BluetoothResultHandler> > mResultHandlerQ;
 
   nsAutoPtr<BluetoothDaemonSocketInterface> mSocketInterface;
   nsAutoPtr<BluetoothDaemonHandsfreeInterface> mHandsfreeInterface;