LoginSignup
0
1

More than 5 years have passed since last update.

BitVisorでUSBキーボードのフック

Last updated at Posted at 2017-12-22

BitVisorのドライバのコード量のおよそ半分を占めるのにもかかわらずほとんど情報がないusbドライバを触ってみようと思います.USBのことは良く分からないので簡単そうなUSBキーボードのフックをしてみます.

前準備

USBキーボードを接続してどこに繋がっているか確認します.

% lsusb
...
Bus 001 Device 010: ID 0853:011d Topre Corporation

% lsusb -t
...
/:  Bus 01.Port 1: Dev 1, Class=root_hub, Driver=xhci_hcd/14p, 480M
    |__ Port 13: Dev 10, If 0, Class=Human Interface Device, Driver=usbhid, 12M

% ls -l /sys/bus/usb/devices/
...
... usb1 -> ../../../devices/pci0000:00/0000:00:14.0/usb1

% cat /sys/bus/usb/devices/1-13/product
Realforce 108U

% lspci -s 00:14.0 -nn
01:14.0 USB controller [0c03]: Intel Corporation 9 Series Chipset Family USB xHCI Controller [8086:8cb1]

キーボードが繋がっているUSBコントローラのDevice ID, Vendor IDが分かったのでdefconfigで以下のようにしてxhciドライバを読み込ませるようにします.

.driver = {
    .pci ="class_code=0c0330,id=8086:8cb1,number=0,driver=xhci",
}

また,configの中でUSBドライバ周りを有効するようにしておきます.(おそらくデフォルトで有効)
さらに,BitVisorが割り込みを捕捉する必要があるため,defconfigの中で.no_intr_intercept = 0を設定しておきます.

フックハンドラの登録

drivers/usb/usb_hid.cを以下のように書き換えます.

#include <core.h>
#include "usb.h"
#include "usb_log.h"
#include "usb_hook.h"
#include "usb_device.h"
#include "uhci.h"

#define USB_ICLASS_HID  0x3
#define USB_PROTOCOL_KEYBOARD  0x1

static int
hid_intercept(struct usb_host *usbhc,
      struct usb_request_block *urb, void *arg)
{
    struct usb_buffer_list *ub;
    for(ub = urb->shadow->buffers; ub; ub = ub->next){
        if (ub->pid != USB_PID_IN)
            continue;
        u8 *cp;
        cp = (u8 *)mapmem_gphys(ub->padr, ub->len, 0);
        for(int i = 0; i < ub->len; i++){
            if(i >= 2 && *cp == 0x1d){ // z
                *cp = 0x04; // a
            }
            cp++;
        }
    }

    return USB_HOOK_PASS;
}

void
usbhid_init_handle (struct usb_host *host, struct usb_device *dev)
{
    u8 class, protocol;
    int i;
    struct usb_interface_descriptor *ides;

    if (!dev || !dev->config || !dev->config->interface ||
        !dev->config->interface->altsetting ||
        !dev->config->interface->num_altsetting) {
        dprintft(1, "HID(%02x): interface descriptor not found.\n",
             dev->devnum);
        return;
    }
    for (i = 0; i < dev->config->interface->num_altsetting; i++) {
        ides = dev->config->interface->altsetting + i;
        class = ides->bInterfaceClass;
        protocol = ides->bInterfaceProtocol;
        if (class == USB_ICLASS_HID && protocol == USB_PROTOCOL_KEYBOARD)
            break;
    }

    if (i == dev->config->interface->num_altsetting)
        return;

    printf("HID(%02x): an USB keyboard found.\n", dev->devnum);

    spinlock_lock(&host->lock_hk);
    struct usb_endpoint_descriptor *epdesc;
    for(i = 1; i <= ides->bNumEndpoints; i++){
        epdesc = &ides->endpoint[i];
        if (epdesc->bEndpointAddress & USB_ENDPOINT_IN) {
            usb_hook_register(host, USB_HOOK_REPLY,
                      USB_HOOK_MATCH_DEV | USB_HOOK_MATCH_ENDP,
                      dev->devnum, epdesc->bEndpointAddress,
                      NULL, hid_intercept, dev, dev);
            printf("HID(%02x, %02x): HID device monitor registered.\n",
                    dev->devnum, epdesc->bEndpointAddress);
        }
    }
    spinlock_unlock(&host->lock_hk);

    return;
}

またdrivers/usb/xhci.c:xhci_new()の末尾付近の適当なところでusb_init_device_monitor()を呼ぶようにします.

static void
xhci_new (struct pci_device *pci_device){
    ...
    usb_init_device_monitor(host->usb_host);
    ...
}

結果

接続したUSBキーボードでzキーを押すとaが入力されます.

補足

BitVisorのusbドライバの動作について参考資料1.に大変分かり易い図があるのでそのまま引用します.

bitvisor_usb.png

USB_HOOK_REPLYを引数としてusb_hook_register()をすると上図の4のところでコールバック関数が呼ばれます.多分.
このときurb->shadow->buffersにUSB通信でやりとりするパケットデータが格納されているようので,そこを直接いじっています.mapmem_gphys()していることから分かるようにゲストの領域を書き換えます.
USBキーボードのデータ構造に関して詳細は参考資料2.を見てください.
Endpoint 0は制御通信用なのでフックからは除外しています.xhci以外で動くのかは試してません.

参考資料

  1. xHCI Driver Implementation
  2. osdev - USB Human Interface Devices
  3. USB Made Simple - Part 5 Typical Human Interface Device (HID)
  4. Intel xHCI manual
0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1