]> git.proxmox.com Git - mirror_qemu.git/blob - hw/usb/u2f-passthru.c
Merge remote-tracking branch 'remotes/huth-gitlab/tags/pull-request-2020-09-16' into...
[mirror_qemu.git] / hw / usb / u2f-passthru.c
1 /*
2 * U2F USB Passthru device.
3 *
4 * Copyright (c) 2020 César Belley <cesar.belley@lse.epita.fr>
5 * Written by César Belley <cesar.belley@lse.epita.fr>
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
20 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23 * THE SOFTWARE.
24 */
25
26 #include "qemu/osdep.h"
27 #include "qemu/module.h"
28 #include "qemu/main-loop.h"
29 #include "qemu/error-report.h"
30 #include "qapi/error.h"
31 #include "hw/qdev-properties.h"
32 #include "hw/usb.h"
33 #include "migration/vmstate.h"
34
35 #include "u2f.h"
36
37 #ifdef CONFIG_LIBUDEV
38 #include <libudev.h>
39 #endif
40 #include <linux/hidraw.h>
41 #include <sys/ioctl.h>
42
43 #define NONCE_SIZE 8
44 #define BROADCAST_CID 0xFFFFFFFF
45 #define TRANSACTION_TIMEOUT 120000
46
47 struct transaction {
48 uint32_t cid;
49 uint16_t resp_bcnt;
50 uint16_t resp_size;
51
52 /* Nonce for broadcast isolation */
53 uint8_t nonce[NONCE_SIZE];
54 };
55
56 typedef struct U2FPassthruState U2FPassthruState;
57
58 #define CURRENT_TRANSACTIONS_NUM 4
59
60 struct U2FPassthruState {
61 U2FKeyState base;
62
63 /* Host device */
64 char *hidraw;
65 int hidraw_fd;
66
67 /* Current Transactions */
68 struct transaction current_transactions[CURRENT_TRANSACTIONS_NUM];
69 uint8_t current_transactions_start;
70 uint8_t current_transactions_end;
71 uint8_t current_transactions_num;
72
73 /* Transaction time checking */
74 int64_t last_transaction_time;
75 QEMUTimer timer;
76 };
77
78 #define TYPE_U2F_PASSTHRU "u2f-passthru"
79 #define PASSTHRU_U2F_KEY(obj) \
80 OBJECT_CHECK(U2FPassthruState, (obj), TYPE_U2F_PASSTHRU)
81
82 /* Init packet sizes */
83 #define PACKET_INIT_HEADER_SIZE 7
84 #define PACKET_INIT_DATA_SIZE (U2FHID_PACKET_SIZE - PACKET_INIT_HEADER_SIZE)
85
86 /* Cont packet sizes */
87 #define PACKET_CONT_HEADER_SIZE 5
88 #define PACKET_CONT_DATA_SIZE (U2FHID_PACKET_SIZE - PACKET_CONT_HEADER_SIZE)
89
90 struct packet_init {
91 uint32_t cid;
92 uint8_t cmd;
93 uint8_t bcnth;
94 uint8_t bcntl;
95 uint8_t data[PACKET_INIT_DATA_SIZE];
96 } QEMU_PACKED;
97
98 static inline uint32_t packet_get_cid(const void *packet)
99 {
100 return *((uint32_t *)packet);
101 }
102
103 static inline bool packet_is_init(const void *packet)
104 {
105 return ((uint8_t *)packet)[4] & (1 << 7);
106 }
107
108 static inline uint16_t packet_init_get_bcnt(
109 const struct packet_init *packet_init)
110 {
111 uint16_t bcnt = 0;
112 bcnt |= packet_init->bcnth << 8;
113 bcnt |= packet_init->bcntl;
114
115 return bcnt;
116 }
117
118 static void u2f_passthru_reset(U2FPassthruState *key)
119 {
120 timer_del(&key->timer);
121 qemu_set_fd_handler(key->hidraw_fd, NULL, NULL, key);
122 key->last_transaction_time = 0;
123 key->current_transactions_start = 0;
124 key->current_transactions_end = 0;
125 key->current_transactions_num = 0;
126 }
127
128 static void u2f_timeout_check(void *opaque)
129 {
130 U2FPassthruState *key = opaque;
131 int64_t time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
132
133 if (time > key->last_transaction_time + TRANSACTION_TIMEOUT) {
134 u2f_passthru_reset(key);
135 } else {
136 timer_mod(&key->timer, time + TRANSACTION_TIMEOUT / 4);
137 }
138 }
139
140 static int u2f_transaction_get_index(U2FPassthruState *key, uint32_t cid)
141 {
142 for (int i = 0; i < key->current_transactions_num; ++i) {
143 int index = (key->current_transactions_start + i)
144 % CURRENT_TRANSACTIONS_NUM;
145 if (cid == key->current_transactions[index].cid) {
146 return index;
147 }
148 }
149 return -1;
150 }
151
152 static struct transaction *u2f_transaction_get(U2FPassthruState *key,
153 uint32_t cid)
154 {
155 int index = u2f_transaction_get_index(key, cid);
156 if (index < 0) {
157 return NULL;
158 }
159 return &key->current_transactions[index];
160 }
161
162 static struct transaction *u2f_transaction_get_from_nonce(U2FPassthruState *key,
163 const uint8_t nonce[NONCE_SIZE])
164 {
165 for (int i = 0; i < key->current_transactions_num; ++i) {
166 int index = (key->current_transactions_start + i)
167 % CURRENT_TRANSACTIONS_NUM;
168 if (key->current_transactions[index].cid == BROADCAST_CID
169 && memcmp(nonce, key->current_transactions[index].nonce,
170 NONCE_SIZE) == 0) {
171 return &key->current_transactions[index];
172 }
173 }
174 return NULL;
175 }
176
177 static void u2f_transaction_close(U2FPassthruState *key, uint32_t cid)
178 {
179 int index, next_index;
180 index = u2f_transaction_get_index(key, cid);
181 if (index < 0) {
182 return;
183 }
184 next_index = (index + 1) % CURRENT_TRANSACTIONS_NUM;
185
186 /* Rearrange to ensure the oldest is at the start position */
187 while (next_index != key->current_transactions_end) {
188 memcpy(&key->current_transactions[index],
189 &key->current_transactions[next_index],
190 sizeof(struct transaction));
191
192 index = next_index;
193 next_index = (index + 1) % CURRENT_TRANSACTIONS_NUM;
194 }
195
196 key->current_transactions_end = index;
197 --key->current_transactions_num;
198
199 if (key->current_transactions_num == 0) {
200 u2f_passthru_reset(key);
201 }
202 }
203
204 static void u2f_transaction_add(U2FPassthruState *key, uint32_t cid,
205 const uint8_t nonce[NONCE_SIZE])
206 {
207 uint8_t index;
208 struct transaction *transaction;
209
210 if (key->current_transactions_num >= CURRENT_TRANSACTIONS_NUM) {
211 /* Close the oldest transaction */
212 index = key->current_transactions_start;
213 transaction = &key->current_transactions[index];
214 u2f_transaction_close(key, transaction->cid);
215 }
216
217 /* Index */
218 index = key->current_transactions_end;
219 key->current_transactions_end = (index + 1) % CURRENT_TRANSACTIONS_NUM;
220 ++key->current_transactions_num;
221
222 /* Transaction */
223 transaction = &key->current_transactions[index];
224 transaction->cid = cid;
225 transaction->resp_bcnt = 0;
226 transaction->resp_size = 0;
227
228 /* Nonce */
229 if (nonce != NULL) {
230 memcpy(transaction->nonce, nonce, NONCE_SIZE);
231 }
232 }
233
234 static void u2f_passthru_read(void *opaque);
235
236 static void u2f_transaction_start(U2FPassthruState *key,
237 const struct packet_init *packet_init)
238 {
239 int64_t time;
240
241 /* Transaction */
242 if (packet_init->cid == BROADCAST_CID) {
243 u2f_transaction_add(key, packet_init->cid, packet_init->data);
244 } else {
245 u2f_transaction_add(key, packet_init->cid, NULL);
246 }
247
248 /* Time */
249 time = qemu_clock_get_ms(QEMU_CLOCK_VIRTUAL);
250 if (key->last_transaction_time == 0) {
251 qemu_set_fd_handler(key->hidraw_fd, u2f_passthru_read, NULL, key);
252 timer_init_ms(&key->timer, QEMU_CLOCK_VIRTUAL, u2f_timeout_check, key);
253 timer_mod(&key->timer, time + TRANSACTION_TIMEOUT / 4);
254 }
255 key->last_transaction_time = time;
256 }
257
258 static void u2f_passthru_recv_from_host(U2FPassthruState *key,
259 const uint8_t packet[U2FHID_PACKET_SIZE])
260 {
261 struct transaction *transaction;
262 uint32_t cid;
263
264 /* Retrieve transaction */
265 cid = packet_get_cid(packet);
266 if (cid == BROADCAST_CID) {
267 struct packet_init *packet_init;
268 if (!packet_is_init(packet)) {
269 return;
270 }
271 packet_init = (struct packet_init *)packet;
272 transaction = u2f_transaction_get_from_nonce(key, packet_init->data);
273 } else {
274 transaction = u2f_transaction_get(key, cid);
275 }
276
277 /* Ignore no started transaction */
278 if (transaction == NULL) {
279 return;
280 }
281
282 if (packet_is_init(packet)) {
283 struct packet_init *packet_init = (struct packet_init *)packet;
284 transaction->resp_bcnt = packet_init_get_bcnt(packet_init);
285 transaction->resp_size = PACKET_INIT_DATA_SIZE;
286
287 if (packet_init->cid == BROADCAST_CID) {
288 /* Nonce checking for legitimate response */
289 if (memcmp(transaction->nonce, packet_init->data, NONCE_SIZE)
290 != 0) {
291 return;
292 }
293 }
294 } else {
295 transaction->resp_size += PACKET_CONT_DATA_SIZE;
296 }
297
298 /* Transaction end check */
299 if (transaction->resp_size >= transaction->resp_bcnt) {
300 u2f_transaction_close(key, cid);
301 }
302 u2f_send_to_guest(&key->base, packet);
303 }
304
305 static void u2f_passthru_read(void *opaque)
306 {
307 U2FPassthruState *key = opaque;
308 U2FKeyState *base = &key->base;
309 uint8_t packet[2 * U2FHID_PACKET_SIZE];
310 int ret;
311
312 /* Full size base queue check */
313 if (base->pending_in_num >= U2FHID_PENDING_IN_NUM) {
314 return;
315 }
316
317 ret = read(key->hidraw_fd, packet, sizeof(packet));
318 if (ret < 0) {
319 /* Detach */
320 if (base->dev.attached) {
321 usb_device_detach(&base->dev);
322 u2f_passthru_reset(key);
323 }
324 return;
325 }
326 if (ret != U2FHID_PACKET_SIZE) {
327 return;
328 }
329 u2f_passthru_recv_from_host(key, packet);
330 }
331
332 static void u2f_passthru_recv_from_guest(U2FKeyState *base,
333 const uint8_t packet[U2FHID_PACKET_SIZE])
334 {
335 U2FPassthruState *key = PASSTHRU_U2F_KEY(base);
336 uint8_t host_packet[U2FHID_PACKET_SIZE + 1];
337 ssize_t written;
338
339 if (packet_is_init(packet)) {
340 u2f_transaction_start(key, (struct packet_init *)packet);
341 }
342
343 host_packet[0] = 0;
344 memcpy(host_packet + 1, packet, U2FHID_PACKET_SIZE);
345
346 written = write(key->hidraw_fd, host_packet, sizeof(host_packet));
347 if (written != sizeof(host_packet)) {
348 error_report("%s: Bad written size (req 0x%zu, val 0x%zd)",
349 TYPE_U2F_PASSTHRU, sizeof(host_packet), written);
350 }
351 }
352
353 static bool u2f_passthru_is_u2f_device(int fd)
354 {
355 int ret, rdesc_size;
356 struct hidraw_report_descriptor rdesc;
357 const uint8_t u2f_hid_report_desc_header[] = {
358 0x06, 0xd0, 0xf1, /* Usage Page (FIDO) */
359 0x09, 0x01, /* Usage (FIDO) */
360 };
361
362 /* Get report descriptor size */
363 ret = ioctl(fd, HIDIOCGRDESCSIZE, &rdesc_size);
364 if (ret < 0 || rdesc_size < sizeof(u2f_hid_report_desc_header)) {
365 return false;
366 }
367
368 /* Get report descriptor */
369 memset(&rdesc, 0x0, sizeof(rdesc));
370 rdesc.size = rdesc_size;
371 ret = ioctl(fd, HIDIOCGRDESC, &rdesc);
372 if (ret < 0) {
373 return false;
374 }
375
376 /* Header bytes cover specific U2F rdesc values */
377 return memcmp(u2f_hid_report_desc_header, rdesc.value,
378 sizeof(u2f_hid_report_desc_header)) == 0;
379 }
380
381 #ifdef CONFIG_LIBUDEV
382 static int u2f_passthru_open_from_device(struct udev_device *device)
383 {
384 const char *devnode = udev_device_get_devnode(device);
385
386 int fd = qemu_open_old(devnode, O_RDWR);
387 if (fd < 0) {
388 return -1;
389 } else if (!u2f_passthru_is_u2f_device(fd)) {
390 qemu_close(fd);
391 return -1;
392 }
393 return fd;
394 }
395
396 static int u2f_passthru_open_from_enumerate(struct udev *udev,
397 struct udev_enumerate *enumerate)
398 {
399 struct udev_list_entry *devices, *entry;
400 int ret, fd;
401
402 ret = udev_enumerate_scan_devices(enumerate);
403 if (ret < 0) {
404 return -1;
405 }
406
407 devices = udev_enumerate_get_list_entry(enumerate);
408 udev_list_entry_foreach(entry, devices) {
409 struct udev_device *device;
410 const char *syspath = udev_list_entry_get_name(entry);
411
412 if (syspath == NULL) {
413 continue;
414 }
415
416 device = udev_device_new_from_syspath(udev, syspath);
417 if (device == NULL) {
418 continue;
419 }
420
421 fd = u2f_passthru_open_from_device(device);
422 udev_device_unref(device);
423 if (fd >= 0) {
424 return fd;
425 }
426 }
427 return -1;
428 }
429
430 static int u2f_passthru_open_from_scan(void)
431 {
432 struct udev *udev;
433 struct udev_enumerate *enumerate;
434 int ret, fd = -1;
435
436 udev = udev_new();
437 if (udev == NULL) {
438 return -1;
439 }
440
441 enumerate = udev_enumerate_new(udev);
442 if (enumerate == NULL) {
443 udev_unref(udev);
444 return -1;
445 }
446
447 ret = udev_enumerate_add_match_subsystem(enumerate, "hidraw");
448 if (ret >= 0) {
449 fd = u2f_passthru_open_from_enumerate(udev, enumerate);
450 }
451
452 udev_enumerate_unref(enumerate);
453 udev_unref(udev);
454
455 return fd;
456 }
457 #endif
458
459 static void u2f_passthru_unrealize(U2FKeyState *base)
460 {
461 U2FPassthruState *key = PASSTHRU_U2F_KEY(base);
462
463 u2f_passthru_reset(key);
464 qemu_close(key->hidraw_fd);
465 }
466
467 static void u2f_passthru_realize(U2FKeyState *base, Error **errp)
468 {
469 U2FPassthruState *key = PASSTHRU_U2F_KEY(base);
470 int fd;
471
472 if (key->hidraw == NULL) {
473 #ifdef CONFIG_LIBUDEV
474 fd = u2f_passthru_open_from_scan();
475 if (fd < 0) {
476 error_setg(errp, "%s: Failed to find a U2F USB device",
477 TYPE_U2F_PASSTHRU);
478 return;
479 }
480 #else
481 error_setg(errp, "%s: Missing hidraw", TYPE_U2F_PASSTHRU);
482 return;
483 #endif
484 } else {
485 fd = qemu_open_old(key->hidraw, O_RDWR);
486 if (fd < 0) {
487 error_setg(errp, "%s: Failed to open %s", TYPE_U2F_PASSTHRU,
488 key->hidraw);
489 return;
490 }
491
492 if (!u2f_passthru_is_u2f_device(fd)) {
493 qemu_close(fd);
494 error_setg(errp, "%s: Passed hidraw does not represent "
495 "a U2F HID device", TYPE_U2F_PASSTHRU);
496 return;
497 }
498 }
499 key->hidraw_fd = fd;
500 u2f_passthru_reset(key);
501 }
502
503 static int u2f_passthru_post_load(void *opaque, int version_id)
504 {
505 U2FPassthruState *key = opaque;
506 u2f_passthru_reset(key);
507 return 0;
508 }
509
510 static const VMStateDescription u2f_passthru_vmstate = {
511 .name = "u2f-key-passthru",
512 .version_id = 1,
513 .minimum_version_id = 1,
514 .post_load = u2f_passthru_post_load,
515 .fields = (VMStateField[]) {
516 VMSTATE_U2F_KEY(base, U2FPassthruState),
517 VMSTATE_END_OF_LIST()
518 }
519 };
520
521 static Property u2f_passthru_properties[] = {
522 DEFINE_PROP_STRING("hidraw", U2FPassthruState, hidraw),
523 DEFINE_PROP_END_OF_LIST(),
524 };
525
526 static void u2f_passthru_class_init(ObjectClass *klass, void *data)
527 {
528 DeviceClass *dc = DEVICE_CLASS(klass);
529 U2FKeyClass *kc = U2F_KEY_CLASS(klass);
530
531 kc->realize = u2f_passthru_realize;
532 kc->unrealize = u2f_passthru_unrealize;
533 kc->recv_from_guest = u2f_passthru_recv_from_guest;
534 dc->desc = "QEMU U2F passthrough key";
535 dc->vmsd = &u2f_passthru_vmstate;
536 device_class_set_props(dc, u2f_passthru_properties);
537 }
538
539 static const TypeInfo u2f_key_passthru_info = {
540 .name = TYPE_U2F_PASSTHRU,
541 .parent = TYPE_U2F_KEY,
542 .instance_size = sizeof(U2FPassthruState),
543 .class_init = u2f_passthru_class_init
544 };
545
546 static void u2f_key_passthru_register_types(void)
547 {
548 type_register_static(&u2f_key_passthru_info);
549 }
550
551 type_init(u2f_key_passthru_register_types)