servo: Merge #11335 - Add WebBluetooth GATTBlacklist support (from szeged:blacklist); r=jdm
authorfokinv <fokinv@inf.u-szeged.hu>
Tue, 31 May 2016 20:00:23 -0500
changeset 338967 b7afa397804274b71efaf09a8745c84d2a80811c
parent 338966 f316678ce66a803d2573ebd52ba0eed11501700a
child 338968 f728a22bff8d6fd27c38a952b9142db0d243005a
push id31307
push usergszorc@mozilla.com
push dateSat, 04 Feb 2017 00:59:06 +0000
treeherdermozilla-central@94079d43835f [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjdm
servo: Merge #11335 - Add WebBluetooth GATTBlacklist support (from szeged:blacklist); r=jdm Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy --faster` does not report any errors - [ ] These changes fix #__ (github issue number if applicable). Either: - [ ] There are tests for these changes OR - [X] These changes do not require tests because there are no webbluetooth tests yet. Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. Source-Repo: https://github.com/servo/servo Source-Revision: 6b1088234bca2643a993dd8b9b809e8a763c03bb
servo/components/script/bluetooth_blacklist.rs
servo/components/script/dom/bluetooth.rs
servo/components/script/dom/bluetoothremotegattcharacteristic.rs
servo/components/script/dom/bluetoothremotegattdescriptor.rs
servo/components/script/dom/bluetoothremotegattserver.rs
servo/components/script/dom/bluetoothremotegattservice.rs
servo/components/script/lib.rs
servo/resources/gatt_blacklist.txt
new file mode 100644
--- /dev/null
+++ b/servo/components/script/bluetooth_blacklist.rs
@@ -0,0 +1,124 @@
+/* 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/. */
+
+use regex::Regex;
+use std::cell::RefCell;
+use std::collections::HashMap;
+use std::io::BufRead;
+use std::string::String;
+use util::resource_files::read_resource_file;
+
+const BLACKLIST_FILE: &'static str = "gatt_blacklist.txt";
+const BLACKLIST_FILE_NOT_FOUND: &'static str = "Could not find gatt_blacklist.txt file";
+const EXCLUDE_READS: &'static str = "exclude-reads";
+const EXCLUDE_WRITES: &'static str = "exclude-writes";
+const VALID_UUID_REGEX: &'static str = "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
+
+thread_local!(pub static BLUETOOTH_BLACKLIST: RefCell<BluetoothBlacklist> =
+              RefCell::new(BluetoothBlacklist(parse_blacklist())));
+
+pub fn uuid_is_blacklisted(uuid: &str, exclude_type: Blacklist) -> bool {
+    BLUETOOTH_BLACKLIST.with(|blist| {
+        match exclude_type {
+            Blacklist::All => {
+                blist.borrow().is_blacklisted(uuid)
+            },
+            Blacklist::Reads => {
+                blist.borrow().is_blacklisted_for_reads(uuid)
+            }
+            Blacklist::Writes => {
+                blist.borrow().is_blacklisted_for_writes(uuid)
+            }
+        }
+    })
+}
+
+pub struct BluetoothBlacklist(Option<HashMap<String, Blacklist>>);
+
+#[derive(Eq, PartialEq)]
+pub enum Blacklist {
+    All, // Read and Write
+    Reads,
+    Writes,
+}
+
+impl BluetoothBlacklist {
+    // https://webbluetoothcg.github.io/web-bluetooth/#blacklisted
+    pub fn is_blacklisted(&self, uuid: &str) -> bool {
+        match self.0 {
+            Some(ref map) => map.get(uuid).map_or(false, |et| et.eq(&Blacklist::All)),
+            None => false,
+        }
+    }
+
+    // https://webbluetoothcg.github.io/web-bluetooth/#blacklisted-for-reads
+    pub fn is_blacklisted_for_reads(&self, uuid: &str) -> bool {
+        match self.0 {
+            Some(ref map) => map.get(uuid).map_or(false, |et| et.eq(&Blacklist::All) ||
+                                                              et.eq(&Blacklist::Reads)),
+            None => false,
+        }
+    }
+
+    // https://webbluetoothcg.github.io/web-bluetooth/#blacklisted-for-writes
+    pub fn is_blacklisted_for_writes(&self, uuid: &str) -> bool {
+        match self.0 {
+            Some(ref map) => map.get(uuid).map_or(false, |et| et.eq(&Blacklist::All) ||
+                                                              et.eq(&Blacklist::Writes)),
+            None => false,
+        }
+    }
+}
+
+// https://webbluetoothcg.github.io/web-bluetooth/#parsing-the-blacklist
+fn parse_blacklist() -> Option<HashMap<String, Blacklist>> {
+    // Step 1 missing, currently we parse ./resources/gatt_blacklist.txt.
+    let valid_uuid_regex = Regex::new(VALID_UUID_REGEX).unwrap();
+    let content = read_resource_file(BLACKLIST_FILE).expect(BLACKLIST_FILE_NOT_FOUND);
+    // Step 3
+    let mut result = HashMap::new();
+    // Step 2 and 4
+    for line in content.lines() {
+        let line = match line {
+            Ok(l) => l,
+            Err(_) => return None,
+        };
+        // Step 4.1
+        if line.is_empty() || line.starts_with('#') {
+            continue;
+        }
+        let mut exclude_type = Blacklist::All;
+        let mut words = line.split_whitespace();
+        let uuid = match words.next() {
+            Some(uuid) => uuid,
+            None => continue,
+        };
+        if !valid_uuid_regex.is_match(uuid) {
+            return None;
+        }
+        match words.next() {
+            // Step 4.2 We already have an initialized exclude_type variable with Blacklist::All.
+            None => {},
+            // Step 4.3
+            Some(EXCLUDE_READS) => {
+                exclude_type = Blacklist::Reads;
+            },
+            Some(EXCLUDE_WRITES) => {
+                exclude_type  = Blacklist::Writes;
+            },
+            // Step 4.4
+            _ => {
+                return None;
+            },
+        }
+        // Step 4.5
+        if result.contains_key(uuid) {
+            return None;
+        }
+        // Step 4.6
+        result.insert(uuid.to_string(), exclude_type);
+    }
+    // Step 5
+    return Some(result);
+}
--- a/servo/components/script/dom/bluetooth.rs
+++ b/servo/components/script/dom/bluetooth.rs
@@ -1,17 +1,18 @@
 /* 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/. */
 
+use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted};
 use core::clone::Clone;
 use dom::bindings::codegen::Bindings::BluetoothBinding;
 use dom::bindings::codegen::Bindings::BluetoothBinding::RequestDeviceOptions;
 use dom::bindings::codegen::Bindings::BluetoothBinding::{BluetoothScanFilter, BluetoothMethods};
-use dom::bindings::error::Error::Type;
+use dom::bindings::error::Error::{Security, Type};
 use dom::bindings::error::Fallible;
 use dom::bindings::global::GlobalRef;
 use dom::bindings::js::Root;
 use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::bluetoothadvertisingdata::BluetoothAdvertisingData;
 use dom::bluetoothdevice::BluetoothDevice;
 use dom::bluetoothuuid::BluetoothUUID;
@@ -66,17 +67,21 @@ fn canonicalize_filter(filter: &Bluetoot
     }
 
     let mut services_vec = vec!();
     if let Some(ref services) = filter.services {
         if services.is_empty() {
             return Err(Type(SERVICE_ERROR.to_owned()));
         }
         for service in services {
-            services_vec.push(try!(BluetoothUUID::GetService(global, service.clone())).to_string());
+            let uuid = try!(BluetoothUUID::GetService(global, service.clone())).to_string();
+            if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+                return Err(Security)
+            }
+            services_vec.push(uuid);
         }
     }
 
     let mut name = String::new();
     if let Some(ref filter_name) = filter.name {
         //NOTE: DOMString::len() gives back the size in bytes
         if filter_name.len() > MAX_DEVICE_NAME_LENGTH {
             return Err(Type(NAME_TOO_LONG_ERROR.to_owned()));
@@ -114,17 +119,21 @@ fn convert_request_device_options(option
     let mut filters = vec!();
     for filter in &options.filters {
         filters.push(try!(canonicalize_filter(&filter, global)));
     }
 
     let mut optional_services = vec!();
     if let Some(ref opt_services) = options.optionalServices {
         for opt_service in opt_services {
-            optional_services.push(try!(BluetoothUUID::GetService(global, opt_service.clone())).to_string());
+            let uuid = try!(BluetoothUUID::GetService(global, opt_service.clone())).to_string();
+            if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+                return Err(Security)
+            }
+            optional_services.push(uuid);
         }
     }
 
     Ok(RequestDeviceoptions::new(BluetoothScanfilterSequence::new(filters),
                                  ServiceUUIDSequence::new(optional_services)))
 }
 
 impl BluetoothMethods for Bluetooth {
--- a/servo/components/script/dom/bluetoothremotegattcharacteristic.rs
+++ b/servo/components/script/dom/bluetoothremotegattcharacteristic.rs
@@ -1,20 +1,21 @@
 /* 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/. */
 
+use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted};
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
     BluetoothRemoteGATTCharacteristicMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
-use dom::bindings::error::Error::{Network, Type};
+use dom::bindings::error::Error::{Network, Security, Type};
 use dom::bindings::error::{Fallible, ErrorResult};
 use dom::bindings::global::GlobalRef;
 use dom::bindings::js::{JS, MutHeap, Root};
 use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
 use dom::bindings::str::{ByteString, DOMString};
 use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
 use dom::bluetoothremotegattdescriptor::BluetoothRemoteGATTDescriptor;
 use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
@@ -88,16 +89,19 @@ impl BluetoothRemoteGATTCharacteristicMe
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-uuid
     fn Uuid(&self) -> DOMString {
         self.uuid.clone()
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptor
     fn GetDescriptor(&self, descriptor: BluetoothDescriptorUUID) -> Fallible<Root<BluetoothRemoteGATTDescriptor>> {
         let uuid = try!(BluetoothUUID::GetDescriptor(self.global().r(), descriptor)).to_string();
+        if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+            return Err(Security)
+        }
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::GetDescriptor(self.get_instance_id(), uuid, sender)).unwrap();
         let descriptor = receiver.recv().unwrap();
         match descriptor {
             Ok(descriptor) => {
                 Ok(BluetoothRemoteGATTDescriptor::new(self.global().r(),
                                                       self,
@@ -111,17 +115,22 @@ impl BluetoothRemoteGATTCharacteristicMe
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-getdescriptors
     fn GetDescriptors(&self,
                       descriptor: Option<BluetoothDescriptorUUID>)
                       -> Fallible<Vec<Root<BluetoothRemoteGATTDescriptor>>> {
         let mut uuid: Option<String> = None;
         if let Some(d) = descriptor {
-            uuid = Some(try!(BluetoothUUID::GetDescriptor(self.global().r(), d)).to_string())
+            uuid = Some(try!(BluetoothUUID::GetDescriptor(self.global().r(), d)).to_string());
+            if let Some(ref uuid) = uuid {
+                if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+                    return Err(Security)
+                }
+            }
         };
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::GetDescriptors(self.get_instance_id(), uuid, sender)).unwrap();
         let descriptors_vec = receiver.recv().unwrap();
         match descriptors_vec {
             Ok(descriptor_vec) => {
                 Ok(descriptor_vec.into_iter()
@@ -139,16 +148,19 @@ impl BluetoothRemoteGATTCharacteristicMe
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-value
     fn GetValue(&self) -> Option<ByteString> {
         self.value.borrow().clone()
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-readvalue
     fn ReadValue(&self) -> Fallible<ByteString> {
+        if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) {
+            return Err(Security)
+        }
         let (sender, receiver) = ipc::channel().unwrap();
         if !self.Service().Device().Gatt().Connected() {
             return Err(Network)
         }
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap();
         let result = receiver.recv().unwrap();
         let value = match result {
@@ -160,16 +172,19 @@ impl BluetoothRemoteGATTCharacteristicMe
             },
         };
         *self.value.borrow_mut() = Some(value.clone());
         Ok(value)
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattcharacteristic-writevalue
     fn WriteValue(&self, value: Vec<u8>) -> ErrorResult {
+        if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) {
+            return Err(Security)
+        }
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap();
         let result = receiver.recv().unwrap();
         match result {
             Ok(_) => Ok(()),
             Err(error) => {
                 Err(Type(error))
--- a/servo/components/script/dom/bluetoothremotegattdescriptor.rs
+++ b/servo/components/script/dom/bluetoothremotegattdescriptor.rs
@@ -1,21 +1,22 @@
 /* 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/. */
 
+use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted};
 use dom::bindings::cell::DOMRefCell;
 use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTCharacteristicBinding::
     BluetoothRemoteGATTCharacteristicMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTDescriptorBinding::BluetoothRemoteGATTDescriptorMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
-use dom::bindings::error::Error::{Type, Network};
+use dom::bindings::error::Error::{Network, Security, Type};
 use dom::bindings::error::{Fallible, ErrorResult};
 use dom::bindings::global::GlobalRef;
 use dom::bindings::js::{JS, MutHeap, Root};
 use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
 use dom::bindings::str::{ByteString, DOMString};
 use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
 use ipc_channel::ipc::{self, IpcSender};
 use net_traits::bluetooth_thread::BluetoothMethodMsg;
@@ -80,16 +81,19 @@ impl BluetoothRemoteGATTDescriptorMethod
 
      // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-value
     fn GetValue(&self) -> Option<ByteString> {
         self.value.borrow().clone()
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-readvalue
     fn ReadValue(&self) -> Fallible<ByteString> {
+        if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Reads) {
+            return Err(Security)
+        }
         let (sender, receiver) = ipc::channel().unwrap();
         if !self.Characteristic().Service().Device().Gatt().Connected() {
             return Err(Network)
         }
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::ReadValue(self.get_instance_id(), sender)).unwrap();
         let result = receiver.recv().unwrap();
         let value = match result {
@@ -101,16 +105,19 @@ impl BluetoothRemoteGATTDescriptorMethod
             },
         };
         *self.value.borrow_mut() = Some(value.clone());
         Ok(value)
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattdescriptor-writevalue
     fn WriteValue(&self, value: Vec<u8>) -> ErrorResult {
+        if uuid_is_blacklisted(self.uuid.as_ref(), Blacklist::Writes) {
+            return Err(Security)
+        }
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::WriteValue(self.get_instance_id(), value, sender)).unwrap();
         let result = receiver.recv().unwrap();
         match result {
             Ok(_) => Ok(()),
             Err(error) => {
                 Err(Type(error))
--- a/servo/components/script/dom/bluetoothremotegattserver.rs
+++ b/servo/components/script/dom/bluetoothremotegattserver.rs
@@ -1,16 +1,17 @@
 /* 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/. */
 
+use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted};
 use dom::bindings::codegen::Bindings::BluetoothDeviceBinding::BluetoothDeviceMethods;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerMethods;
-use dom::bindings::error::Error::Type;
+use dom::bindings::error::Error::{Security, Type};
 use dom::bindings::error::{Fallible, ErrorResult};
 use dom::bindings::global::GlobalRef;
 use dom::bindings::js::{JS, MutHeap, Root};
 use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::bluetoothdevice::BluetoothDevice;
 use dom::bluetoothremotegattservice::BluetoothRemoteGATTService;
 use dom::bluetoothuuid::{BluetoothServiceUUID, BluetoothUUID};
@@ -91,16 +92,19 @@ impl BluetoothRemoteGATTServerMethods fo
                 Err(Type(error))
             },
         }
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservice
     fn GetPrimaryService(&self, service: BluetoothServiceUUID) -> Fallible<Root<BluetoothRemoteGATTService>> {
         let uuid = try!(BluetoothUUID::GetService(self.global().r(), service)).to_string();
+        if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+            return Err(Security)
+        }
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::GetPrimaryService(String::from(self.Device().Id()), uuid, sender)).unwrap();
         let service = receiver.recv().unwrap();
         match service {
             Ok(service) => {
                 Ok(BluetoothRemoteGATTService::new(self.global().r(),
                                                    &self.device.get(),
@@ -115,17 +119,22 @@ impl BluetoothRemoteGATTServerMethods fo
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattserver-getprimaryservices
     fn GetPrimaryServices(&self,
                           service: Option<BluetoothServiceUUID>)
                           -> Fallible<Vec<Root<BluetoothRemoteGATTService>>> {
         let mut uuid: Option<String> = None;
         if let Some(s) = service {
-            uuid = Some(try!(BluetoothUUID::GetService(self.global().r(), s)).to_string())
+            uuid = Some(try!(BluetoothUUID::GetService(self.global().r(), s)).to_string());
+            if let Some(ref uuid) = uuid {
+                if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+                    return Err(Security)
+                }
+            }
         };
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::GetPrimaryServices(String::from(self.Device().Id()), uuid, sender)).unwrap();
         let services_vec = receiver.recv().unwrap();
         match services_vec {
             Ok(service_vec) => {
                 Ok(service_vec.into_iter()
--- a/servo/components/script/dom/bluetoothremotegattservice.rs
+++ b/servo/components/script/dom/bluetoothremotegattservice.rs
@@ -1,15 +1,16 @@
 /* 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/. */
 
+use bluetooth_blacklist::{Blacklist, uuid_is_blacklisted};
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding;
 use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServiceBinding::BluetoothRemoteGATTServiceMethods;
-use dom::bindings::error::Error::Type;
+use dom::bindings::error::Error::{Security, Type};
 use dom::bindings::error::Fallible;
 use dom::bindings::global::GlobalRef;
 use dom::bindings::js::{JS, MutHeap, Root};
 use dom::bindings::reflector::{Reflectable, Reflector, reflect_dom_object};
 use dom::bindings::str::DOMString;
 use dom::bluetoothcharacteristicproperties::BluetoothCharacteristicProperties;
 use dom::bluetoothdevice::BluetoothDevice;
 use dom::bluetoothremotegattcharacteristic::BluetoothRemoteGATTCharacteristic;
@@ -83,16 +84,19 @@ impl BluetoothRemoteGATTServiceMethods f
         self.uuid.clone()
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristic
     fn GetCharacteristic(&self,
                          characteristic: BluetoothCharacteristicUUID)
                          -> Fallible<Root<BluetoothRemoteGATTCharacteristic>> {
         let uuid = try!(BluetoothUUID::GetCharacteristic(self.global().r(), characteristic)).to_string();
+        if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+            return Err(Security)
+        }
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::GetCharacteristic(self.get_instance_id(), uuid, sender)).unwrap();
         let characteristic = receiver.recv().unwrap();
         match characteristic {
             Ok(characteristic) => {
                 let properties = BluetoothCharacteristicProperties::new(self.global().r(),
                                                                         characteristic.broadcast,
@@ -117,17 +121,22 @@ impl BluetoothRemoteGATTServiceMethods f
     }
 
     // https://webbluetoothcg.github.io/web-bluetooth/#dom-bluetoothremotegattservice-getcharacteristics
     fn GetCharacteristics(&self,
                           characteristic: Option<BluetoothCharacteristicUUID>)
                           -> Fallible<Vec<Root<BluetoothRemoteGATTCharacteristic>>> {
         let mut uuid: Option<String> = None;
         if let Some(c) = characteristic {
-            uuid = Some(try!(BluetoothUUID::GetCharacteristic(self.global().r(), c)).to_string())
+            uuid = Some(try!(BluetoothUUID::GetCharacteristic(self.global().r(), c)).to_string());
+            if let Some(ref uuid) = uuid {
+                if uuid_is_blacklisted(uuid.as_ref(), Blacklist::All) {
+                    return Err(Security)
+                }
+            }
         };
         let mut characteristics = vec!();
         let (sender, receiver) = ipc::channel().unwrap();
         self.get_bluetooth_thread().send(
             BluetoothMethodMsg::GetCharacteristics(self.get_instance_id(), uuid, sender)).unwrap();
         let characteristics_vec = receiver.recv().unwrap();
         match characteristics_vec {
             Ok(characteristic_vec) => {
--- a/servo/components/script/lib.rs
+++ b/servo/components/script/lib.rs
@@ -82,16 +82,17 @@ extern crate unicase;
 extern crate url;
 #[macro_use]
 extern crate util;
 extern crate uuid;
 extern crate webrender_traits;
 extern crate websocket;
 extern crate xml5ever;
 
+pub mod bluetooth_blacklist;
 pub mod clipboard_provider;
 pub mod cors;
 mod devtools;
 pub mod document_loader;
 #[macro_use]
 pub mod dom;
 pub mod layout_interface;
 mod mem;
new file mode 100644
--- /dev/null
+++ b/servo/resources/gatt_blacklist.txt
@@ -0,0 +1,53 @@
+# Source:
+# https://github.com/WebBluetoothCG/registries/blob/master/gatt_blacklist.txt
+# License:
+# https://github.com/WebBluetoothCG/registries/blob/master/LICENSE
+
+# This file holds a list of GATT UUIDs that websites using the Web
+# Bluetooth API are forbidden from accessing.
+
+## Services
+
+# org.bluetooth.service.human_interface_device
+# Direct access to HID devices like keyboards would let web pages
+# become keyloggers.
+00001812-0000-1000-8000-00805f9b34fb
+
+# Firmware update services that don't check the update's signature
+# present a risk of devices' software being modified by malicious web
+# pages. Users may connect to a device believing they are enabling
+# only simple interaction or that they're interacting with the
+# device's manufacturer, but the site might instead persistently
+# compromise the device.
+#
+# Nordic's Device Firmware Update service, http://infocenter.nordicsemi.com/topic/com.nordic.infocenter.sdk5.v11.0.0/examples_ble_dfu.html:
+00001530-1212-efde-1523-785feabcd123
+# TI's Over-the-Air Download service, http://www.ti.com/lit/ug/swru271g/swru271g.pdf:
+f000ffc0-0451-4000-b000-000000000000
+
+
+## Characteristics
+
+# org.bluetooth.characteristic.gap.peripheral_privacy_flag
+# Don't let web pages turn off privacy mode.
+00002a02-0000-1000-8000-00805f9b34fb exclude-writes
+
+# org.bluetooth.characteristic.gap.reconnection_address
+# Disallow messing with connection parameters
+00002a03-0000-1000-8000-00805f9b34fb
+
+# org.bluetooth.characteristic.serial_number_string
+# Block access to standardized unique identifiers, for privacy reasons.
+00002a25-0000-1000-8000-00805f9b34fb
+
+
+## Descriptors
+
+# org.bluetooth.descriptor.gatt.client_characteristic_configuration
+# Writing to this would let a web page interfere with other pages'
+# notifications and indications.
+00002902-0000-1000-8000-00805f9b34fb exclude-writes
+
+# org.bluetooth.descriptor.gatt.server_characteristic_configuration
+# Writing to this would let a web page interfere with the broadcasted services.
+00002903-0000-1000-8000-00805f9b34fb exclude-writes
\ No newline at end of file