blob: 4e57b089ccb8ae93563ff2b3792139466d8cb1eb [file] [log] [blame]
// 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(
udev_device_get_subsystem(other_device.get()))) <<
"This rule should IGNORE claimed devices.";
}
}
} else if (result != Rule::DENY) {
FAIL() << "This rule should only either IGNORE or DENY devices.";
}
}
}
} // namespace permission_broker