blob: 26b40e444559e011f39aa2478e56f758ff7d1c3e [file] [log] [blame]
// Copyright 2019 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_fwupdate_hidraw_device_rule.h"
#include <libudev.h>
#include <string>
#include <unordered_map>
#include <vector>
#include "base/files/file_path.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
namespace {
const int kElanVendorId = 0x04f3;
const int kMelfasVendorId = 0x1fd2;
// Structure that holds a map of vendor IDs and a list of the blocked product ID
// ranges. These ranges are inclusive.
const permission_broker::RangeListMap kFwUpdateDevices = {
// Block ELAN touchscreens PID 0x2000 - 0x2FFF and 0x4000 - 0x4FFF. 0x0732
// is the PID for a device in recovery mode.
{kElanVendorId, {{0x2000, 0x2fff}, {0x4000, 0x4fff}, {0x0732, 0x0732}}},
// Melfas USB touchscreen PID 0x8103.
{kMelfasVendorId, {{0x8103, 0x8103}}},
};
} // namespace
namespace permission_broker {
DenyFwUpdateHidrawDeviceRule::DenyFwUpdateHidrawDeviceRule()
: HidrawSubsystemUdevRule("DenyFwUpdateHidrawDeviceRule") {}
Rule::Result DenyFwUpdateHidrawDeviceRule::ProcessHidrawDevice(
struct udev_device* device) {
const char* devpath = udev_device_get_devpath(device);
return IsFwUpdateDevice(devpath, kFwUpdateDevices) ? Rule::DENY
: Rule::IGNORE;
}
// The vendor and device ID are not in the udev properties. They need to be
// parsed out of the device path:
// e.g. i2c-7/i2c-ELAN900C:00/0018:04F3:2A03.0001/hidraw/hidraw0. The
// important part of the path is 0018:04F3:2A03.0001 where 04F3 is the vendor
// ID and 2A03 is the product ID.
bool DenyFwUpdateHidrawDeviceRule::IsFwUpdateDevice(
const char* path, const RangeListMap& fwDevices) {
if (!path) {
return false;
}
// Split the path by directories.
std::vector<std::string> dirs;
base::FilePath(path).GetComponents(&dirs);
for (const auto& dir : dirs) {
// Split the path by colons (:). We are searching for the pattern:
// ####:####:####.####
// All devices that match this pattern need to be checked to ensure that
// none are disallowed.
std::vector<std::string> chunks =
base::SplitString(dir, ":", base::WhitespaceHandling::TRIM_WHITESPACE,
base::SplitResult::SPLIT_WANT_NONEMPTY);
if (chunks.size() != 3) {
continue;
}
// The vendor ID is the second hex value in the sequence.
int vendor_id;
if (!base::HexStringToInt(chunks[1], &vendor_id)) {
continue;
}
// The product ID is the third hex value in the sequence. The period and
// trailing numbers also need to be trimmed.
std::string::size_type pos = chunks[2].find('.');
int product_id;
if (!base::HexStringToInt(chunks[2].substr(0, pos), &product_id)) {
continue;
}
if (fwDevices.count(vendor_id) != 1) {
continue;
}
for (const auto& range : fwDevices.at(vendor_id)) {
if (product_id >= range.min && product_id <= range.max) {
return true;
}
}
}
return false;
}
} // namespace permission_broker