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
5 use std::fs::File;
6 use std::os::raw::c_int;
7
8 use base::handle_eintr_errno;
9 use base::ioctl_ior_nr;
10
11 use crate::usb::backend::fido_backend::constants;
12 use crate::usb::backend::fido_backend::error::Error;
13 use crate::usb::backend::fido_backend::error::Result;
14
15 #[repr(C)]
16 #[derive(Clone)]
17 pub struct HidrawReportDescriptor {
18 pub size: u32,
19 pub value: [u8; constants::HID_MAX_DESCRIPTOR_SIZE],
20 }
21
22 pub const HID_IO_TYPE: u32 = 'H' as u32;
23
24 ioctl_ior_nr!(HIDIOCGRDESCSIZE, HID_IO_TYPE, 0x01, c_int);
25 ioctl_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.
verify_is_fido_device(hidraw: &File) -> Result<()>29 pub 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 }
73