Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 32 additions & 1 deletion src/transport/linux/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,28 @@ use crate::transport::hid::HIDDevice;
use crate::transport::platform::{hidraw, monitor};
use crate::transport::{FidoDevice, FidoProtocol, HIDError, SharedSecret};
use crate::u2ftypes::U2FDeviceInfo;
use crate::util::from_unix_result;
use crate::util::{from_unix_result, io_err};
use std::fs::OpenOptions;
use std::hash::{Hash, Hasher};
use std::io;
use std::io::{Read, Write};
use std::os::unix::io::AsRawFd;
use std::path::PathBuf;

/// USB HID read timeout, in milliseconds.
///
/// This is needed to prevent devices (particularly virtual `uhid` bridge devices) that *don't*
/// respond in a timely manner from [causing the browser to hang][0].
///
/// [CTAP 2.3 §11.2.9.1.7][1] says devices SHOULD send `CTAPHID_KEEPALIVE` every 100ms while
/// processing a `CTAPHID_MSG` or `CTAPHID_CBOR`. This gives devices 2 seconds to send a
/// `CTAPHID_KEEPALIVE`. [`HIDDevice::sendrecv`][] lets an application interrupt an authenticator
/// sending `CTAPHID_KEEPALIVE` forever.
///
/// [0]: https://bugzilla.mozilla.org/show_bug.cgi?id=1958831
/// [1]: https://fidoalliance.og/specs/fido-v2.3-ps-20260226/fido-client-to-authenticator-protocol-v2.3-ps-20260226.html#usb-hid-keepalive
const READ_TIMEOUT: i32 = 2000;

#[derive(Debug)]
pub struct Device {
path: PathBuf,
Expand Down Expand Up @@ -50,6 +64,23 @@ impl Hash for Device {

impl Read for Device {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
// Check that we can actually read from the device.
let mut pfd = libc::pollfd {
fd: self.fd.as_raw_fd(),
events: libc::POLLIN,
revents: 0,
};
let nfds = unsafe { libc::poll(&mut pfd, 1, READ_TIMEOUT) };
if nfds == -1 || pfd.revents & libc::POLLERR != 0 {
return Err(io::Error::last_os_error());
}
if pfd.revents & libc::POLLNVAL != 0 {
return Err(io::Error::from_raw_os_error(libc::EBADF));
}
if nfds == 0 || pfd.revents & libc::POLLIN == 0 {
return Err(io_err("no response from device"));
}

Comment thread
micolous marked this conversation as resolved.
let bufp = buf.as_mut_ptr() as *mut libc::c_void;
let rv = unsafe { libc::read(self.fd.as_raw_fd(), bufp, buf.len()) };
from_unix_result(rv as usize)
Expand Down
Loading