devices/usb/backend/fido_backend/
hid_utils.rs

1// Copyright 2024 The ChromiumOS Authors
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::fs::File;
6use std::os::raw::c_int;
7
8use base::handle_eintr_errno;
9use base::ioctl_ior_nr;
10
11use crate::usb::backend::fido_backend::constants;
12use crate::usb::backend::fido_backend::error::Error;
13use crate::usb::backend::fido_backend::error::Result;
14
15#[repr(C)]
16#[derive(Clone)]
17pub struct HidrawReportDescriptor {
18    pub size: u32,
19    pub value: [u8; constants::HID_MAX_DESCRIPTOR_SIZE],
20}
21
22pub const HID_IO_TYPE: u32 = 'H' as u32;
23
24ioctl_ior_nr!(HIDIOCGRDESCSIZE, HID_IO_TYPE, 0x01, c_int);
25ioctl_ior_nr!(HIDIOCGRDESC, HID_IO_TYPE, 0x02, HidrawReportDescriptor);
26
27/// Verifies that the given `hidraw` file handle is a valid FIDO device.
28/// In case it is not, it returns an `InvalidHidrawDevice` erro.
29pub fn verify_is_fido_device(hidraw: &File) -> Result<()> {
30    let mut desc_size: c_int = 0;
31    // SAFETY:
32    // Safe because:
33    // - We check the return value after the call.
34    // - ioctl(HIDIOCGRDDESCSIZE) does not hold the descriptor after the call.
35    unsafe {
36        let ret = handle_eintr_errno!(base::ioctl_with_mut_ref(
37            hidraw,
38            HIDIOCGRDESCSIZE,
39            &mut desc_size
40        ));
41        if ret < 0 || (desc_size as usize) < constants::HID_REPORT_DESC_HEADER.len() {
42            return Err(Error::InvalidHidrawDevice);
43        }
44    }
45
46    let mut descriptor = HidrawReportDescriptor {
47        size: desc_size as u32,
48        value: [0; constants::HID_MAX_DESCRIPTOR_SIZE],
49    };
50
51    // SAFETY:
52    // Safe because:
53    // - We check the return value after the call.
54    // - ioctl(HIDIOCGRDESC) does not hold the descriptor after the call.
55    unsafe {
56        let ret = handle_eintr_errno!(base::ioctl_with_mut_ref(
57            hidraw,
58            HIDIOCGRDESC,
59            &mut descriptor
60        ));
61        if ret < 0 {
62            return Err(Error::InvalidHidrawDevice);
63        }
64    }
65
66    if descriptor.value[..constants::HID_REPORT_DESC_HEADER.len()]
67        != *constants::HID_REPORT_DESC_HEADER
68    {
69        return Err(Error::InvalidHidrawDevice);
70    }
71    Ok(())
72}