| // Copyright 2014 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "permission_broker/deny_claimed_hidraw_device_rule.h" |
| |
| #include <gtest/gtest.h> |
| #include <libudev.h> |
| |
| #include <string> |
| |
| #include "permission_broker/udev_scopers.h" |
| |
| namespace permission_broker { |
| |
| class DenyClaimedHidrawDeviceRuleTest : public testing::Test { |
| public: |
| DenyClaimedHidrawDeviceRuleTest() : udev_(udev_new()) {} |
| |
| ~DenyClaimedHidrawDeviceRuleTest() override = default; |
| |
| protected: |
| ScopedUdevPtr udev_; |
| DenyClaimedHidrawDeviceRule rule_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(DenyClaimedHidrawDeviceRuleTest); |
| }; |
| |
| TEST_F(DenyClaimedHidrawDeviceRuleTest, DenyClaimedHidrawDevices) { |
| // Run the rule on every available device and verify that it only ignores |
| // unclaimed USB HID devices, denying the rest. |
| ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev_.get())); |
| udev_enumerate_add_match_subsystem(enumerate.get(), "hidraw"); |
| udev_enumerate_scan_devices(enumerate.get()); |
| struct udev_list_entry* entry = NULL; |
| udev_list_entry_foreach(entry, |
| udev_enumerate_get_list_entry(enumerate.get())) { |
| const char *syspath = udev_list_entry_get_name(entry); |
| ScopedUdevDevicePtr device( |
| udev_device_new_from_syspath(udev_.get(), syspath)); |
| Rule::Result result = rule_.ProcessHidrawDevice(device.get()); |
| |
| // This device was ignored by the rule. Make sure that it's a USB device |
| // and that it's USB interface is not, in fact, being used by other drivers. |
| if (result == Rule::IGNORE) { |
| struct udev_device* usb_interface = |
| udev_device_get_parent_with_subsystem_devtype( |
| device.get(), "usb", "usb_interface"); |
| |
| ASSERT_TRUE(usb_interface != NULL) << |
| "This rule should DENY all non-USB HID devices."; |
| |
| std::string usb_interface_path(udev_device_get_syspath(usb_interface)); |
| |
| // Verify that this hidraw device does not share a USB interface with any |
| // other drivers' devices. This means we have to enumerate every device |
| // to find any with the same ancestral usb_interface, then test for a non- |
| // generic subsystem. |
| ScopedUdevEnumeratePtr other_enumerate(udev_enumerate_new(udev_.get())); |
| udev_enumerate_scan_devices(other_enumerate.get()); |
| struct udev_list_entry* other_entry = NULL; |
| udev_list_entry_foreach( |
| other_entry, |
| udev_enumerate_get_list_entry(other_enumerate.get())) { |
| const char* other_path = udev_list_entry_get_name(other_entry); |
| ScopedUdevDevicePtr other_device( |
| udev_device_new_from_syspath(udev_.get(), other_path)); |
| struct udev_device* other_usb_interface = |
| udev_device_get_parent_with_subsystem_devtype( |
| other_device.get(), "usb", "usb_interface"); |
| if (!other_usb_interface) { |
| continue; |
| } |
| std::string other_usb_interface_path( |
| udev_device_get_syspath(other_usb_interface)); |
| if (usb_interface_path == other_usb_interface_path) { |
| ASSERT_FALSE( |
| DenyClaimedHidrawDeviceRule:: |
| ShouldSiblingSubsystemExcludeHidAccess(other_device.get())) |
| << "This rule should IGNORE claimed devices."; |
| } |
| } |
| } else if (result != Rule::DENY) { |
| FAIL() << "This rule should only either IGNORE or DENY devices."; |
| } |
| } |
| } |
| |
| TEST_F(DenyClaimedHidrawDeviceRuleTest, InputCapabilityExclusions) { |
| const char* kKeyboardKeys; |
| const char* kMouseKeys; |
| const char* kHeadsetKeys; |
| const char* kBrailleKeys; |
| |
| // The size of these bitfield chunks is the width of a userspace long. |
| switch (sizeof(long)) { // NOLINT(runtime/int) |
| case 4: |
| kKeyboardKeys = |
| "10000 00000007 ff9f207a c14057ff " |
| "febeffdf ffefffff ffffffff fffffffe"; |
| kMouseKeys = |
| "1f0000 0 0 0 0 0 0 0 0"; |
| kHeadsetKeys = |
| "18000 178 0 8e0000 0 0 0"; |
| kBrailleKeys = |
| "7fe0000 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0"; |
| break; |
| case 8: |
| kKeyboardKeys = |
| "1000000000007 ff9f207ac14057ff febeffdfffefffff fffffffffffffffe"; |
| kMouseKeys = |
| "1f0000 0 0 0 0"; |
| kHeadsetKeys = |
| "18000 17800000000 8e000000000000 0"; |
| kBrailleKeys = |
| "7fe000000000000 0 0 0 0 0 0 0"; |
| break; |
| default: |
| FAIL() << "Unsupported platform long width."; |
| } |
| |
| // Example capabilities from a real keyboard. Should be excluded. |
| EXPECT_TRUE( |
| DenyClaimedHidrawDeviceRule::ShouldInputCapabilitiesExcludeHidAccess( |
| "0", "0", kKeyboardKeys)); |
| |
| // Example capabilities from a real mouse. Should be excluded. |
| EXPECT_TRUE( |
| DenyClaimedHidrawDeviceRule::ShouldInputCapabilitiesExcludeHidAccess( |
| "0", "103", kMouseKeys)); |
| |
| // Example capabilities from a headset with some telephony buttons. Should not |
| // be excluded. |
| EXPECT_FALSE( |
| DenyClaimedHidrawDeviceRule::ShouldInputCapabilitiesExcludeHidAccess( |
| "0", "0", kHeadsetKeys)); |
| |
| // A braille input device (made up). Should be excluded. |
| EXPECT_TRUE( |
| DenyClaimedHidrawDeviceRule::ShouldInputCapabilitiesExcludeHidAccess( |
| "0", "0", kBrailleKeys)); |
| } |
| |
| } // namespace permission_broker |