blob: 026c6e2eb5321dba920c74958da73e9d788dc0c7 [file] [log] [blame]
// Copyright (c) 2012 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_usb_device_rule.h"
#include <gtest/gtest.h>
#include <libudev.h>
#include <set>
#include <string>
#include "base/logging.h"
#include "base/stl_util.h"
#include "base/strings/string_number_conversions.h"
#include "permission_broker/rule_test.h"
#include "permission_broker/udev_scopers.h"
using std::set;
using std::string;
namespace permission_broker {
class DenyClaimedUsbDeviceRuleMockPolicy : public DenyClaimedUsbDeviceRule {
public:
DenyClaimedUsbDeviceRuleMockPolicy() = default;
DenyClaimedUsbDeviceRuleMockPolicy(
const DenyClaimedUsbDeviceRuleMockPolicy&) = delete;
DenyClaimedUsbDeviceRuleMockPolicy& operator=(
const DenyClaimedUsbDeviceRuleMockPolicy&) = delete;
~DenyClaimedUsbDeviceRuleMockPolicy() override = default;
void SetMockedUsbAllowList(
const std::vector<policy::DevicePolicy::UsbDeviceId>& allowed) {
usb_allow_list_ = allowed;
}
private:
bool LoadPolicy() override { return true; }
};
class DenyClaimedUsbDeviceRuleTest : public RuleTest {
public:
DenyClaimedUsbDeviceRuleTest() = default;
DenyClaimedUsbDeviceRuleTest(const DenyClaimedUsbDeviceRuleTest&) = delete;
DenyClaimedUsbDeviceRuleTest& operator=(const DenyClaimedUsbDeviceRuleTest&) =
delete;
~DenyClaimedUsbDeviceRuleTest() override = default;
protected:
void SetUp() override {
ScopedUdevPtr udev(udev_new());
ScopedUdevEnumeratePtr enumerate(udev_enumerate_new(udev.get()));
udev_enumerate_scan_devices(enumerate.get());
struct udev_list_entry* entry = nullptr;
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));
EXPECT_TRUE(device.get());
const char* devtype = udev_device_get_devtype(device.get());
if (!devtype || strcmp(devtype, "usb_interface") != 0)
continue;
struct udev_device* parent = udev_device_get_parent(device.get());
if (!parent)
continue;
const char* devnode = udev_device_get_devnode(parent);
if (!devnode)
continue;
const char* vid = udev_device_get_sysattr_value(parent, "idVendor");
const char* pid = udev_device_get_sysattr_value(parent, "idProduct");
unsigned vendor_id, product_id;
if (!vid || !base::HexStringToUInt(vid, &vendor_id))
continue;
if (!pid || !base::HexStringToUInt(pid, &product_id))
continue;
policy::DevicePolicy::UsbDeviceId id;
id.vendor_id = vendor_id;
id.product_id = product_id;
string path = devnode;
const char* driver = udev_device_get_driver(device.get());
if (!base::Contains(partially_claimed_devices_, path)) {
if (driver) {
auto it = unclaimed_devices_.find(path);
if (it == unclaimed_devices_.end()) {
claimed_devices_.insert(path);
if (strcmp(driver, "hub") != 0) {
detachable_allow_list_.push_back(id);
detachable_devices_.insert(path);
}
} else {
partially_claimed_devices_.insert(path);
unclaimed_devices_.erase(it);
}
} else {
auto it = claimed_devices_.find(path);
if (it == claimed_devices_.end()) {
unclaimed_devices_.insert(path);
} else {
partially_claimed_devices_.insert(path);
claimed_devices_.erase(it);
}
}
}
}
}
DenyClaimedUsbDeviceRuleMockPolicy rule_;
set<string> claimed_devices_;
set<string> unclaimed_devices_;
set<string> partially_claimed_devices_;
set<string> detachable_devices_;
std::vector<policy::DevicePolicy::UsbDeviceId> detachable_allow_list_;
};
TEST_F(DenyClaimedUsbDeviceRuleTest, IgnoreNonUsbDevice) {
ASSERT_EQ(Rule::IGNORE, rule_.ProcessDevice(FindDevice("/dev/tty0").get()));
}
TEST_F(DenyClaimedUsbDeviceRuleTest, DenyClaimedUsbDevice) {
if (claimed_devices_.empty())
LOG(WARNING) << "Tests incomplete because there are no claimed devices "
<< "connected.";
for (const string& device : claimed_devices_)
EXPECT_EQ(Rule::DENY, rule_.ProcessDevice(FindDevice(device).get()))
<< device;
}
TEST_F(DenyClaimedUsbDeviceRuleTest, IgnoreUnclaimedUsbDevice) {
if (unclaimed_devices_.empty())
LOG(WARNING) << "Tests incomplete because there are no unclaimed devices "
<< "connected.";
for (const string& device : unclaimed_devices_)
EXPECT_EQ(Rule::IGNORE, rule_.ProcessDevice(FindDevice(device).get()))
<< device;
}
TEST_F(DenyClaimedUsbDeviceRuleTest,
AllowPartiallyClaimedUsbDeviceWithLockdown) {
if (partially_claimed_devices_.empty())
LOG(WARNING) << "Tests incomplete because there are no partially claimed "
<< "devices connected.";
for (const string& device : partially_claimed_devices_)
EXPECT_EQ(Rule::ALLOW_WITH_LOCKDOWN,
rule_.ProcessDevice(FindDevice(device).get()))
<< device;
}
TEST_F(DenyClaimedUsbDeviceRuleTest, AllowDetachableClaimedUsbDevice) {
if (detachable_devices_.empty())
LOG(WARNING) << "Tests incomplete because there are no detachable "
<< "devices connected.";
rule_.SetMockedUsbAllowList(detachable_allow_list_);
for (const string& device : detachable_devices_)
EXPECT_EQ(Rule::ALLOW_WITH_DETACH,
rule_.ProcessDevice(FindDevice(device).get()))
<< device;
}
} // namespace permission_broker