qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

u2f-passthru.c (15663B)


      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     set_bit(DEVICE_CATEGORY_MISC, dc->categories);
    538 }
    539 
    540 static const TypeInfo u2f_key_passthru_info = {
    541     .name = TYPE_U2F_PASSTHRU,
    542     .parent = TYPE_U2F_KEY,
    543     .instance_size = sizeof(U2FPassthruState),
    544     .class_init = u2f_passthru_class_init
    545 };
    546 
    547 static void u2f_key_passthru_register_types(void)
    548 {
    549     type_register_static(&u2f_key_passthru_info);
    550 }
    551 
    552 type_init(u2f_key_passthru_register_types)