From patchwork Tue Jun 25 14:53:47 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Bouman X-Patchwork-Id: 13711771 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id DF581C2BBCA for ; Tue, 25 Jun 2024 17:37:33 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sM9xC-0001JQ-P8; Tue, 25 Jun 2024 13:27:46 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sM7Yp-0003cB-Iq for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:19 -0400 Received: from mail-ed1-x534.google.com ([2a00:1450:4864:20::534]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sM7Yo-0003GF-0U for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:19 -0400 Received: by mail-ed1-x534.google.com with SMTP id 4fb4d7f45d1cf-57cc1c00b97so5574308a12.0 for ; Tue, 25 Jun 2024 07:54:17 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719327255; x=1719932055; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=gd1bnX5yMsLjKAf/zlmApEfZTYiMqAMKaFxN5Ze85Yc=; b=i3gBoxlrtqBamK0ytEM0RYFDW1E67Q08WQxMa9FsiHACz4RoB7x60IHfMTOGTHBw97 4iLaAfynHRCzdKjXlIetMfFs8/M0Xv/ur8YACVuCItyGEwxuLFy1gfy3qPhI35w4WDXY Z0N9coGVi5iikR5A2wiNu4Ybq0kFqcZ90Ega4bTsqd47wfwY+KqgfTszhCYi5AAbj/Rn lpiWvVreDolD3YUYmpkEwKCdlFyJAo4qSppCz6Nl13AwMSZW276eCFwOfTj7Nnd4TtLD 8smgBvMmcbiYic9YDppc6y8KTcUwoiekIEz5cBEDUl4sL2SSTxVO4vCJE6ga7HNVq3Fz MBSQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719327255; x=1719932055; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=gd1bnX5yMsLjKAf/zlmApEfZTYiMqAMKaFxN5Ze85Yc=; b=TienmJYXb+BFYhpTseUSPTnKilWXUySjOict4xfWiDiN8hB5oHmT4qVeQSu5Nx0i1u 8a+HlXOKYPQeoHzZN1mBQHgBzA/C8dvNP2yQpF28S5RLe15pE0OEIy/Rtg5htq8JszyL cc30JZ7ujzepsxB1vuVPcOhTdbqleFnNLE4ps2OqH+LBdFHtpP9Pe47Nq6jj3FUo0+kE CI+lEbi3XzdDH7bxkl+RxHDswJ4zLYAMid/66exmmpl6wx9FdBnM2C+tmqETVemMWyhh QUvcsZq7D23TicdN+Laozu8AC5SRldzFXswxszCxUNP8jEHDptS2FNNjTJMvNmOdrV40 ixBg== X-Gm-Message-State: AOJu0Yz/pQlGDmLq10s7RRmjGX0oV9hfYjze4BrpYdHkL0NySG4a6nTU 3aERC0xlARZIsPfRyTXYKWLjddHEyFUbIrEfah9FvecUox5cusdn4OSbbQ== X-Google-Smtp-Source: AGHT+IGqX5yA+0k3VJ5/KXQ+ampjX9TzFY8KWbpglDZmONHaMBeigDL/BjTd77zUURHG4QynOlWREA== X-Received: by 2002:a50:aa96:0:b0:57d:788:aaae with SMTP id 4fb4d7f45d1cf-57d4bddfabamr6098598a12.35.1719327255483; Tue, 25 Jun 2024 07:54:15 -0700 (PDT) Received: from 41414141.home (84-82-177-210.fixed.kpn.net. [84.82.177.210]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-57d3042d421sm6092740a12.42.2024.06.25.07.54.14 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Jun 2024 07:54:15 -0700 (PDT) From: David Bouman To: qemu-devel@nongnu.org Cc: David Bouman Subject: [PATCH 1/4] hw/usb/u2f: Add `start` and `stop` callbacks to U2F key class Date: Tue, 25 Jun 2024 16:53:47 +0200 Message-Id: <20240625145350.65978-2-dbouman03@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240625145350.65978-1-dbouman03@gmail.com> References: <20240625145350.65978-1-dbouman03@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::534; envelope-from=dbouman03@gmail.com; helo=mail-ed1-x534.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 25 Jun 2024 13:25:46 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Preparation for improved u2f-passthru hidraw handle lifetimes: These callbacks can be implemented by the backing implementation, i.e. u2f-passthru or u2f-emulated. The start callback is invoked when the device receives an INTR IN, and the stop callback is invoked when the endpoint has been unlinked/stopped. For a Linux guest, the start callback corresponds to the `hid_hw_open` and `hid_hw_close` routines, invoked whenever the first user opens, respectively the last user closes the emulated hidraw device. Signed-off-by: David Bouman --- hw/usb/u2f.c | 23 +++++++++++++++++++++++ hw/usb/u2f.h | 5 +++++ 2 files changed, 28 insertions(+) diff --git a/hw/usb/u2f.c b/hw/usb/u2f.c index 1fb59cf404..cc1abd6c7d 100644 --- a/hw/usb/u2f.c +++ b/hw/usb/u2f.c @@ -253,6 +253,12 @@ static void u2f_key_handle_data(USBDevice *dev, USBPacket *p) case USB_TOKEN_IN: packet_in = u2f_pending_in_get(key); if (packet_in == NULL) { + U2FKeyClass *kc = U2F_KEY_GET_CLASS(key); + + /* An early INTR IN is sent to kick the device. */ + if (!key->started) { + key->started = (kc->start ? kc->start(key) : true); + } p->status = USB_RET_NAK; return; } @@ -317,6 +323,21 @@ const VMStateDescription vmstate_u2f_key = { } }; +static void u2f_ep_stopped(USBDevice *dev, USBEndpoint *ep) +{ + U2FKeyState *key = U2F_KEY(dev); + U2FKeyClass *kc = U2F_KEY_GET_CLASS(key); + + if (!key->started) { + return; + } + if (kc->stop) { + kc->stop(key); + } + key->started = false; +} + + static void u2f_key_class_init(ObjectClass *klass, void *data) { DeviceClass *dc = DEVICE_CLASS(klass); @@ -332,6 +353,8 @@ static void u2f_key_class_init(ObjectClass *klass, void *data) uc->unrealize = u2f_key_unrealize; dc->desc = "QEMU U2F key"; dc->vmsd = &vmstate_u2f_key; + + uc->ep_stopped = u2f_ep_stopped; } static const TypeInfo u2f_key_info = { diff --git a/hw/usb/u2f.h b/hw/usb/u2f.h index 8bff13141a..56d989c783 100644 --- a/hw/usb/u2f.h +++ b/hw/usb/u2f.h @@ -49,6 +49,9 @@ struct U2FKeyClass { const uint8_t packet[U2FHID_PACKET_SIZE]); void (*realize)(U2FKeyState *key, Error **errp); void (*unrealize)(U2FKeyState *key); + + bool (*start)(U2FKeyState *key); + void (*stop)(U2FKeyState *key); }; /* @@ -64,6 +67,8 @@ struct U2FKeyState { uint8_t pending_in_start; uint8_t pending_in_end; uint8_t pending_in_num; + + bool started; }; /* From patchwork Tue Jun 25 14:53:48 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Bouman X-Patchwork-Id: 13711767 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 4C469C2BBCA for ; Tue, 25 Jun 2024 17:36:55 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sM9xb-0001TE-Qc; Tue, 25 Jun 2024 13:28:12 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sM7Ys-0003e6-Qa for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:22 -0400 Received: from mail-ed1-x52d.google.com ([2a00:1450:4864:20::52d]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sM7Yr-0003Gl-4O for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:22 -0400 Received: by mail-ed1-x52d.google.com with SMTP id 4fb4d7f45d1cf-57cbc66a0a6so399786a12.1 for ; Tue, 25 Jun 2024 07:54:20 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719327259; x=1719932059; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=rbbUSVqqZXzZF+3uTUU0bNtjkD7QAaruiWfpJ52dpCQ=; b=k0CWagpBtv4+5W0IJODAw9qwFKM9Z9PZAEy3SD0nHKZ5K95Je7Jttffjs7J3NZCDqp q5FWBr7/FjovZgraXAhAwVBl5E0PDw21Rtjr3jgXRS8g4Q2iJPTj7JftKcHJMHMuMrOS +r0stSr/Xhy4hSa+qWXhdmFV72Q/P+9ZKqXWbJaRu81HzG/5iRZdchSDmXztcltaYun1 c4iE/dZjMnetc40mrM5nN+1mu6bRh06ebeSChJlTCWrs5BxejjPknMIKRf/y/udCcbgW R3llabukIbOjKtl/tzkEBQABJVymlv/SSQ9BoTpEqFyEqNhdNmANixPMfBVpuLnivXmK hzog== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719327259; x=1719932059; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=rbbUSVqqZXzZF+3uTUU0bNtjkD7QAaruiWfpJ52dpCQ=; b=FAxIV1wp4efuX4gLTc7lADwYqV53iozV21BCTql9nDaES5nMJPD6UjvycvAgcq0UsB UABquyY8W9v8FZwW4TTLyJPG4sj0B6m+6F4C0+g3PQzIhp71NURle7M17xH0pgb1YEDJ xXW1unKzx+w25LXOXhDYZ6a2DKTvG7djEOUn3+z6e1lYdwG65kpll0/n+nRK/q/UyOhj NeUzYQqwtRXmosl1kwajEhwjnAMIDqsgA2kNH1NVqRxcVdU6VaqUKaTvBAu6fWoe5sZ+ weh0225AiukMMyDpEdFkxI6bwrxbjvRVPJdcuswX7NhZfHn6gtChup0GxIo86qnB6QvO 9Ang== X-Gm-Message-State: AOJu0Yyl+qYie8zZ5iRrXz3ZnWYwdEQn12+nhLFc6cFx7EMZZLOrR+12 CFz6Z/upwws7Dr+2YHuDIDsnvp+lgDcDycqLiRiyC+Qpmc9RGGGcaMFTzw== X-Google-Smtp-Source: AGHT+IExjcGqP/+Yp+argbQqFMrMDhox0o8HA00ZaFqhGJVKN1W1DTcm4/KzQKeeuJ+pIrMnTlt14Q== X-Received: by 2002:aa7:d6cd:0:b0:57d:22a1:25cc with SMTP id 4fb4d7f45d1cf-57d447e24f5mr6569334a12.8.1719327259154; Tue, 25 Jun 2024 07:54:19 -0700 (PDT) Received: from 41414141.home (84-82-177-210.fixed.kpn.net. [84.82.177.210]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-57d3042d421sm6092740a12.42.2024.06.25.07.54.18 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Jun 2024 07:54:18 -0700 (PDT) From: David Bouman To: qemu-devel@nongnu.org Cc: David Bouman Subject: [PATCH 2/4] hw/usb/u2f-passthru: Do not needlessly retain handle to hidraw chardev Date: Tue, 25 Jun 2024 16:53:48 +0200 Message-Id: <20240625145350.65978-3-dbouman03@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240625145350.65978-1-dbouman03@gmail.com> References: <20240625145350.65978-1-dbouman03@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::52d; envelope-from=dbouman03@gmail.com; helo=mail-ed1-x52d.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 25 Jun 2024 13:25:46 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org The Linux kernel presumes a hidraw device to be "active" as long as an open handle to its character device exists, and during that time will actively poll its bus for new messages. The u2f-passthru device keeps an open handle to the hidraw character device for its entire lifetime, wasting power and causing its queue to be clogged with irrelevant packets that were not initiated by the guest. To mitigate this, use the u2f `start` and `stop` callbacks to dynamically open the handle when the guest is about to use the u2f-passthru device (start callback), and close it again whenever the guest stops using it (stop callback). Signed-off-by: David Bouman Fixes: 299976b050bf (hw/usb: Add U2F key passthru mode) --- hw/usb/u2f-passthru.c | 84 +++++++++++++++++++++++++++++++------------ 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c index b7025d303d..54062ab4d5 100644 --- a/hw/usb/u2f-passthru.c +++ b/hw/usb/u2f-passthru.c @@ -118,7 +118,10 @@ static inline uint16_t packet_init_get_bcnt( static void u2f_passthru_reset(U2FPassthruState *key) { timer_del(&key->timer); - qemu_set_fd_handler(key->hidraw_fd, NULL, NULL, key); + + if (key->hidraw_fd >= 0) { + qemu_set_fd_handler(key->hidraw_fd, NULL, NULL, key); + } key->last_transaction_time = 0; key->current_transactions_start = 0; key->current_transactions_end = 0; @@ -456,47 +459,79 @@ static int u2f_passthru_open_from_scan(void) } #endif -static void u2f_passthru_unrealize(U2FKeyState *base) -{ - U2FPassthruState *key = PASSTHRU_U2F_KEY(base); - - u2f_passthru_reset(key); - qemu_close(key->hidraw_fd); -} -static void u2f_passthru_realize(U2FKeyState *base, Error **errp) +static int u2f_passthru_open_hidraw(U2FPassthruState *key, Error** errp) { - U2FPassthruState *key = PASSTHRU_U2F_KEY(base); int fd; - if (key->hidraw == NULL) { #ifdef CONFIG_LIBUDEV fd = u2f_passthru_open_from_scan(); - if (fd < 0) { + + if (fd < 0 && errp) { error_setg(errp, "%s: Failed to find a U2F USB device", TYPE_U2F_PASSTHRU); - return; } #else - error_setg(errp, "%s: Missing hidraw", TYPE_U2F_PASSTHRU); - return; + if (errp) { + error_setg(errp, "%s: Missing hidraw", TYPE_U2F_PASSTHRU); + } + return -1; #endif } else { fd = qemu_open_old(key->hidraw, O_RDWR); - if (fd < 0) { + + if (fd < 0 && errp) { error_setg(errp, "%s: Failed to open %s", TYPE_U2F_PASSTHRU, key->hidraw); - return; - } - if (!u2f_passthru_is_u2f_device(fd)) { + } else if (!u2f_passthru_is_u2f_device(fd)) { qemu_close(fd); - error_setg(errp, "%s: Passed hidraw does not represent " - "a U2F HID device", TYPE_U2F_PASSTHRU); - return; + if (errp) { + error_setg(errp, "%s: Passed hidraw does not represent " + "a U2F HID device", TYPE_U2F_PASSTHRU); + } + return -1; } } - key->hidraw_fd = fd; + + return fd; +} + +static bool u2f_passthru_start(U2FKeyState *base) +{ + U2FPassthruState *key = PASSTHRU_U2F_KEY(base); + + if (key->hidraw_fd < 0) { + key->hidraw_fd = u2f_passthru_open_hidraw(key, NULL); + } + return key->hidraw_fd >= 0; +} + +static void u2f_passthru_stop(U2FKeyState *base) +{ + U2FPassthruState *key = PASSTHRU_U2F_KEY(base); + + u2f_passthru_reset(key); + if (key->hidraw_fd >= 0) { + qemu_close(key->hidraw_fd); + key->hidraw_fd = -1; + } +} + +static void u2f_passthru_unrealize(U2FKeyState *base) +{ + u2f_passthru_stop(base); +} +static void u2f_passthru_realize(U2FKeyState *base, Error **errp) +{ + U2FPassthruState *key = PASSTHRU_U2F_KEY(base); + int fd = u2f_passthru_open_hidraw(key, errp); + + /* we only open the fd to error at start */ + if (fd >= 0) { + qemu_close(fd); + } + key->hidraw_fd = -1; u2f_passthru_reset(key); } @@ -531,6 +566,9 @@ static void u2f_passthru_class_init(ObjectClass *klass, void *data) kc->realize = u2f_passthru_realize; kc->unrealize = u2f_passthru_unrealize; kc->recv_from_guest = u2f_passthru_recv_from_guest; + kc->start = u2f_passthru_start; + kc->stop = u2f_passthru_stop; + dc->desc = "QEMU U2F passthrough key"; dc->vmsd = &u2f_passthru_vmstate; device_class_set_props(dc, u2f_passthru_properties); From patchwork Tue Jun 25 14:53:49 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Bouman X-Patchwork-Id: 13711769 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 3ABD2C2BBCA for ; Tue, 25 Jun 2024 17:37:03 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sM9wA-0000wg-6G; Tue, 25 Jun 2024 13:26:39 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sM7Yv-0003fS-QA for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:25 -0400 Received: from mail-ed1-x532.google.com ([2a00:1450:4864:20::532]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sM7Yt-0003IY-W4 for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:25 -0400 Received: by mail-ed1-x532.google.com with SMTP id 4fb4d7f45d1cf-57cbc66a0a6so399885a12.1 for ; Tue, 25 Jun 2024 07:54:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719327262; x=1719932062; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=QCyejyP/ZmZFgO98LacfQCNiAcBDIeycsTCAxZG7mtU=; b=Z4V+Q/3Fr4fYd3Z1KirZ14VzeAhNHZdvqUCdHbQn0cQpaNuekZ5J72coUOpOeqeXEG 5bBDRasHZphY4M+fCv57n70yYe2+KsR68FsgMuDZwG97nCJeWi2/VW58A1mRxZn24c84 griSHAHFtCjXgRAUCHCNRQb790K3aCjJYJRXybeFLxuFgFVFNROGWVDDeAwc7hJrpWfF D8oHT/k4ONwt2pxt/MKW+tQtCZ1MX4uj1HlPoQRrKPW7uK3yJkgcdwzwexdzsP5bThVs DQCiDilHjDkrb2llm5IhxkstEbmtIA+vjfgLtzuGuLLHJtuQ+t9LCMPzKgo83byoZqFu TvSg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719327262; x=1719932062; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=QCyejyP/ZmZFgO98LacfQCNiAcBDIeycsTCAxZG7mtU=; b=lPWZ+Wz0nzihZgNgNd1LaVuINuF3AzZuyeLZrRP+JprLQk/bxNiqgGd2ao8K5pGlkn 6ziFivnm4qQXMba4gcC139XD6fLMGdvpQI/BPhHgbMgeE3j5j+thuV+nSxEGoyzvYAT+ YAzI0OiGg2BzKb3C3hUjf29iFf1gzYXFkySLjwg92rNa47+ravxPrfKqeqeuwEccQ54R XKBJ6iJqz5Pk2Pf2blu1MClZBv8nFWFEDZzRtMbLgW9EgfJzPJFIBwmaT5ba97ARPwqZ DafW7PFJC7IA0uBK4HNzAoyyqpSM60B9iMaze81EGxMzWqvhCoknB/FBykVxvOTCv4Xt awtg== X-Gm-Message-State: AOJu0YyQm+zY0sJ1wowZoaka/XGL5c1K89LcuaD9sG2lIouOIbUKIhdW rL3C+F3j2UMcssxJDpSXaDBZthxZXFqnqAY376fosgK6bmSR4iZeS72cGw== X-Google-Smtp-Source: AGHT+IEirtFrpGKzLsTuornSmFt0JxKdS9u92cY+RQiVGGOROmTJGwMyEtOl7/iugJQqNFuP2N1a9g== X-Received: by 2002:a50:a694:0:b0:57d:df3:4cf2 with SMTP id 4fb4d7f45d1cf-57d701ee10bmr2349281a12.11.1719327262300; Tue, 25 Jun 2024 07:54:22 -0700 (PDT) Received: from 41414141.home (84-82-177-210.fixed.kpn.net. [84.82.177.210]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-57d3042d421sm6092740a12.42.2024.06.25.07.54.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Jun 2024 07:54:21 -0700 (PDT) From: David Bouman To: qemu-devel@nongnu.org Cc: David Bouman Subject: [PATCH 3/4] hw/usb/u2f-passthru: Clean up code Date: Tue, 25 Jun 2024 16:53:49 +0200 Message-Id: <20240625145350.65978-4-dbouman03@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240625145350.65978-1-dbouman03@gmail.com> References: <20240625145350.65978-1-dbouman03@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::532; envelope-from=dbouman03@gmail.com; helo=mail-ed1-x532.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 25 Jun 2024 13:25:47 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Prepare for implementing the FIDO-U2F keepalive feature: Represent all u2fhid frames using one coherent structure, and make casts explicit. Signed-off-by: David Bouman --- hw/usb/u2f-passthru.c | 73 ++++++++++++++++++++++++++----------------- 1 file changed, 44 insertions(+), 29 deletions(-) diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c index 54062ab4d5..d0fb7b377c 100644 --- a/hw/usb/u2f-passthru.c +++ b/hw/usb/u2f-passthru.c @@ -87,30 +87,45 @@ struct U2FPassthruState { #define PACKET_CONT_HEADER_SIZE 5 #define PACKET_CONT_DATA_SIZE (U2FHID_PACKET_SIZE - PACKET_CONT_HEADER_SIZE) -struct packet_init { +/* Frame definition */ + +#define U2FHID_CMD_PING 0x81 +#define U2FHID_CMD_MSG 0x83 +#define U2FHID_CMD_INIT 0x86 +#define U2FHID_CMD_WINK 0x88 +#define U2FHID_CMD_CBOR 0x90 +#define U2FHID_CMD_CANCEL 0x91 +#define U2FHID_CMD_KEEPALIVE 0xbb +#define U2FHID_ERROR 0xbf + +struct u2fhid_frame { uint32_t cid; - uint8_t cmd; - uint8_t bcnth; - uint8_t bcntl; - uint8_t data[PACKET_INIT_DATA_SIZE]; + union { + uint8_t type; + struct { + uint8_t cmd; + uint8_t bcnth; + uint8_t bcntl; + uint8_t data[PACKET_INIT_DATA_SIZE]; + } init; + struct { + uint8_t seq; + uint8_t data[PACKET_CONT_DATA_SIZE]; + } cont; + }; } QEMU_PACKED; -static inline uint32_t packet_get_cid(const void *packet) +static inline bool packet_is_init(struct u2fhid_frame *packet) { - return *((uint32_t *)packet); -} - -static inline bool packet_is_init(const void *packet) -{ - return ((uint8_t *)packet)[4] & (1 << 7); + return !!(packet->type & (1 << 7)); } static inline uint16_t packet_init_get_bcnt( - const struct packet_init *packet_init) + const struct u2fhid_frame *packet) { uint16_t bcnt = 0; - bcnt |= packet_init->bcnth << 8; - bcnt |= packet_init->bcntl; + bcnt |= (uint16_t)(packet->init.bcnth) << 8; + bcnt |= packet->init.bcntl; return bcnt; } @@ -237,13 +252,13 @@ static void u2f_transaction_add(U2FPassthruState *key, uint32_t cid, static void u2f_passthru_read(void *opaque); static void u2f_transaction_start(U2FPassthruState *key, - const struct packet_init *packet_init) + const struct u2fhid_frame *packet_init) { int64_t time; /* Transaction */ if (packet_init->cid == BROADCAST_CID) { - u2f_transaction_add(key, packet_init->cid, packet_init->data); + u2f_transaction_add(key, packet_init->cid, packet_init->init.data); } else { u2f_transaction_add(key, packet_init->cid, NULL); } @@ -259,20 +274,19 @@ static void u2f_transaction_start(U2FPassthruState *key, } static void u2f_passthru_recv_from_host(U2FPassthruState *key, - const uint8_t packet[U2FHID_PACKET_SIZE]) + const uint8_t raw_packet[U2FHID_PACKET_SIZE]) { struct transaction *transaction; uint32_t cid; + struct u2fhid_frame *packet = (void *)raw_packet; /* Retrieve transaction */ - cid = packet_get_cid(packet); + cid = packet->cid; if (cid == BROADCAST_CID) { - struct packet_init *packet_init; if (!packet_is_init(packet)) { return; } - packet_init = (struct packet_init *)packet; - transaction = u2f_transaction_get_from_nonce(key, packet_init->data); + transaction = u2f_transaction_get_from_nonce(key, packet->init.data); } else { transaction = u2f_transaction_get(key, cid); } @@ -283,13 +297,12 @@ static void u2f_passthru_recv_from_host(U2FPassthruState *key, } if (packet_is_init(packet)) { - struct packet_init *packet_init = (struct packet_init *)packet; - transaction->resp_bcnt = packet_init_get_bcnt(packet_init); + transaction->resp_bcnt = packet_init_get_bcnt(packet); transaction->resp_size = PACKET_INIT_DATA_SIZE; - if (packet_init->cid == BROADCAST_CID) { + if (packet->cid == BROADCAST_CID) { /* Nonce checking for legitimate response */ - if (memcmp(transaction->nonce, packet_init->data, NONCE_SIZE) + if (memcmp(transaction->nonce, packet->init.data, NONCE_SIZE) != 0) { return; } @@ -302,7 +315,7 @@ static void u2f_passthru_recv_from_host(U2FPassthruState *key, if (transaction->resp_size >= transaction->resp_bcnt) { u2f_transaction_close(key, cid); } - u2f_send_to_guest(&key->base, packet); + u2f_send_to_guest(&key->base, raw_packet); } static void u2f_passthru_read(void *opaque) @@ -333,14 +346,16 @@ static void u2f_passthru_read(void *opaque) } static void u2f_passthru_recv_from_guest(U2FKeyState *base, - const uint8_t packet[U2FHID_PACKET_SIZE]) + const uint8_t raw_packet[U2FHID_PACKET_SIZE]) { U2FPassthruState *key = PASSTHRU_U2F_KEY(base); uint8_t host_packet[U2FHID_PACKET_SIZE + 1]; ssize_t written; + struct u2fhid_frame *packet = (void *)raw_packet; + if (packet_is_init(packet)) { - u2f_transaction_start(key, (struct packet_init *)packet); + u2f_transaction_start(key, packet); } host_packet[0] = 0; From patchwork Tue Jun 25 14:53:50 2024 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: David Bouman X-Patchwork-Id: 13711770 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from lists.gnu.org (lists.gnu.org [209.51.188.17]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.lore.kernel.org (Postfix) with ESMTPS id 8FE82C3064D for ; Tue, 25 Jun 2024 17:37:25 +0000 (UTC) Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sM9ys-00022O-U4; Tue, 25 Jun 2024 13:29:31 -0400 Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sM7Yx-0003iz-Hz for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:27 -0400 Received: from mail-ed1-x530.google.com ([2a00:1450:4864:20::530]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sM7Yv-0003Ih-QA for qemu-devel@nongnu.org; Tue, 25 Jun 2024 10:54:27 -0400 Received: by mail-ed1-x530.google.com with SMTP id 4fb4d7f45d1cf-57d20d89748so5472806a12.0 for ; Tue, 25 Jun 2024 07:54:25 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1719327264; x=1719932064; darn=nongnu.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=FTEABTvUlmGhewuD80/IM0/j/3yvJVyKCKjnPPFuNU0=; b=k8HYSXgd51oJj2eU40HRf/HIBE+3Du/YmvD+/xaCUftsZsmKY4W52lbpHunHHd2G2b WYEjX9X+geTYDM4W/Kf5IVt1Q+5sqSYw6UcNoLd/Gyo/Wg/3TPiBFc2l1QPgNXdjtzLN yCO6ynYV8PXX60f8ZrVqlDngKdpxKUjFkV2fPyHTpu0jai0H0YN1i5xQgoTJ/m4PGT+E c6rH1SJkkMd0R6dnCYTLA9UeOX0XesBR0svcDG7m21lyZqAwtk7qeUvZkfrwyN40xjI0 wT6Kz2mVB+mTH5qkG9AMTK4keLaua5bgSVCfbuH6e0O+bheDBLte0qxLxMk/0wVO1KpB w2eA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1719327264; x=1719932064; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=FTEABTvUlmGhewuD80/IM0/j/3yvJVyKCKjnPPFuNU0=; b=tsEr1NAqyOhdOecHBkxXHhA7HTmYCSW1g6TOVzUSAKCtpwkn+pnAH2rTUNXA7W/2fi sVU+QcUffss9nWgXmTWQlTBh0XaNkt5SrOHzhUUHJIfppEoQ1lJ/ws+INT88gQQmUhK5 KxMDzffMitIZFbcO0t6cDMQ2r2y4b9dfDfniTStozY5XYczoAckp049xhzzTfKueEpKq HTXj8rpX8vukqtzq+mxjOxqu0WwW5Ac4DZPSfUfF/Yu9m0PfQzuP5Oms5hqyH2bgt2yg NB96VkZAbXGNjluCvlsnXVDO6YODsGqut1C7OkYFgZ4I+MSLx0VP3hEkKfYatAA3Gp4/ fSTg== X-Gm-Message-State: AOJu0YzG4BgFuz2eC/KmckTMZ/07IezynkMWUThUuO+7F+jHxBjvzX/W E8dbgf4yI+IwQUyKOEILw7sss4VyjhiaRR90KX3aCMQvFkmFFZQfl7zexA== X-Google-Smtp-Source: AGHT+IHX12OXseF02pCwYdu3uF8zcxfHzMRAHLlJqHuLhiPN/zKgFHLh+cXRKPot5fkv3+UKKUv1uQ== X-Received: by 2002:a50:8ad7:0:b0:57d:692:33ee with SMTP id 4fb4d7f45d1cf-57d4a03eba4mr5905730a12.36.1719327264064; Tue, 25 Jun 2024 07:54:24 -0700 (PDT) Received: from 41414141.home (84-82-177-210.fixed.kpn.net. [84.82.177.210]) by smtp.gmail.com with ESMTPSA id 4fb4d7f45d1cf-57d3042d421sm6092740a12.42.2024.06.25.07.54.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 25 Jun 2024 07:54:23 -0700 (PDT) From: David Bouman To: qemu-devel@nongnu.org Cc: David Bouman Subject: [PATCH 4/4] hw/usb/u2f-passthru: Implement FIDO U2FHID keep-alive Date: Tue, 25 Jun 2024 16:53:50 +0200 Message-Id: <20240625145350.65978-5-dbouman03@gmail.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20240625145350.65978-1-dbouman03@gmail.com> References: <20240625145350.65978-1-dbouman03@gmail.com> MIME-Version: 1.0 Received-SPF: pass client-ip=2a00:1450:4864:20::530; envelope-from=dbouman03@gmail.com; helo=mail-ed1-x530.google.com X-Spam_score_int: -17 X-Spam_score: -1.8 X-Spam_bar: - X-Spam_report: (-1.8 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_ENVFROM_END_DIGIT=0.25, FREEMAIL_FROM=0.001, RCVD_IN_DNSWL_NONE=-0.0001, SPF_HELO_NONE=0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-Mailman-Approved-At: Tue, 25 Jun 2024 13:25:51 -0400 X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org Sender: qemu-devel-bounces+qemu-devel=archiver.kernel.org@nongnu.org FIDO U2FHID features a keep-alive response command (code 0xbb). A keep-alive response signifies that the request is being processed and the transaction should not be closed yet. u2f-passthru does not recognize this command, and hence closes the transaction prematurely upon receiving it. This prevents some U2F security keys from being passed through correctly (Yubikey 4/5). Fix this by recognizing the keep-alive response and, if received, by keeping the transaction alive regardless of the resp_bcnt limit. Signed-off-by: David Bouman Fixes: 299976b050bf (hw/usb: Add U2F key passthru mode) Resolves: https://gitlab.com/qemu-project/qemu/-/issues/2293 --- hw/usb/u2f-passthru.c | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hw/usb/u2f-passthru.c b/hw/usb/u2f-passthru.c index d0fb7b377c..c1e4db3467 100644 --- a/hw/usb/u2f-passthru.c +++ b/hw/usb/u2f-passthru.c @@ -296,10 +296,14 @@ static void u2f_passthru_recv_from_host(U2FPassthruState *key, return; } + bool keepalive = false; if (packet_is_init(packet)) { transaction->resp_bcnt = packet_init_get_bcnt(packet); transaction->resp_size = PACKET_INIT_DATA_SIZE; + if (packet->init.cmd == U2FHID_CMD_KEEPALIVE) + keepalive = true; + if (packet->cid == BROADCAST_CID) { /* Nonce checking for legitimate response */ if (memcmp(transaction->nonce, packet->init.data, NONCE_SIZE) @@ -312,7 +316,7 @@ static void u2f_passthru_recv_from_host(U2FPassthruState *key, } /* Transaction end check */ - if (transaction->resp_size >= transaction->resp_bcnt) { + if (!keepalive && transaction->resp_size >= transaction->resp_bcnt) { u2f_transaction_close(key, cid); } u2f_send_to_guest(&key->base, raw_packet);