BitVisorのソースコード中のマジックナンバーを理解する

これは BitVisor Advent Calendar 2018 の8日目の記事です．

皆さーん，BitVisor のソースコードを読んでますかー！
私はあちこち読んでます．
BitVisor のソースコードには，精神を落ち着かせる効果があるように思います（意識をいつの間にか失っているという点で）．

最近は悪い人間になった気分で，BitVisor を乗っ取れる脆弱性を探すことに凝っています．まだ見つけられていないのですけれども．

BitVisor のソースコードには謎のマジックナンバーが時々出てきます．それらは何を意味しているのでしょうか．

マジックナンバーがありそうな行を grep で抽出します．6桁以上数字が並んでいて，かつ，0000を含まない行を．

```
bitvisor-2.0$ grep -r "[0-9]\{6,\}" . | grep -v 0000 | wc -l
3181
```
結構あります．でもほとんどは暗号か LwIP かスマートカードに関係するコードの行です．あと，hgtags の行もあります．それらを削ります．

```
bitvisor-2.0$ grep -r "[0-9]\{6,\}" . | grep -v 0000 | grep -v crypto | grep -v lwip | grep -v SCARD  | grep -v hgtags | wc -l
109
```

109行まで絞れました．結果はこんな感じです．

```
./bitvisor-2.0/vpn/lib/Se/SePacket.h:#define    SE_DHCPV4_MAGIC_COOKIE  0x63825363      // Magic Cookie (固定)
./bitvisor-2.0/vpn/lib/Se/SeMemory.c:   ((UINT *)p)[0] = 0x12345678;
./bitvisor-2.0/vpn/lib/Se/SeMemory.c:   if (((UINT *)real_addr)[0] != 0x12345678)
./bitvisor-2.0/vpn/lib/Se/SeMemory.c:   ((UINT *)p)[0] = 0x12345678;
./bitvisor-2.0/vpn/lib/Se/SeMemory.c:   if (((UINT *)real_addr)[0] != 0x12345678)
./bitvisor-2.0/vpn/lib/Se/SeMemory.c:   if (((UINT *)real_addr)[0] != 0x12345678)
./bitvisor-2.0/vpn/lib/Se/SeCrypto.h:   "E485B576625E7EC6F44C42E9A637ED6B0BFF5CB6F406B7ED" \
./bitvisor-2.0/vpn/lib/Se/SeCrypto.h:   "EE386BFB5A899FA5AE9F24117C4B1FE649286651ECE65381" \
./bitvisor-2.0/vpn/lib/Se/SeKernel.c:           ret = (UINT64)tick + (UINT64)rt->TickRoundCounter * 4294967296ULL;
./bitvisor-2.0/vpn/lib/Se/SeStr.c:                                      value64 = value64 + (UINT64)(UINT)((unsigned long)pvalue2) * 4294967296ULL;
./bitvisor-2.0/boot/loader/bootloader.s:        movl    $0x400010,(%si)         # size of packet (0x10) and 0x40 blocks
./bitvisor-2.0/boot/login/conf/bitvisor.conf.tmpl:#storage.conf0.lba_high=12851999
./bitvisor-2.0/boot/login/conf/bitvisor.conf.tmpl:storage.conf0.lba_low=527478210
./bitvisor-2.0/boot/login/conf/bitvisor.conf.tmpl:storage.conf0.lba_high=605602304
./bitvisor-2.0/boot/login/conf/bitvisor.conf.tmpl:storage.conf2.lba_high=1409024
./bitvisor-2.0/boot/login/minios_init/boot.h:   struct config_data config; /* 0x00100010 */
./bitvisor-2.0/boot/login/minios_init/usbmem.c: packet->signature = 0x43425355;
./bitvisor-2.0/boot/login/minios_init/usbmem.c: packet->signature = 0x43425355;
./bitvisor-2.0/boot/login/minios_init/boot.c:   0xBB, 0x00100010,
./bitvisor-2.0/boot/login/minios_init/boot.c:   /* 0x00100010- config */
./bitvisor-2.0/boot/uefi-loader/loadvmm.c:      msg[0] = L"0123456789ABCDEF"[val & 0xF];
./bitvisor-2.0/boot/uefi-loader-login/loadvmm.c:        msg[0] = L"0123456789ABCDEF"[val & 0xF];
./bitvisor-2.0/boot/login-simple/bitvisor.conf.tmpl:#storage.conf0.lba_high=12851999
./bitvisor-2.0/boot/login-simple/bitvisor.conf.tmpl:storage.conf0.lba_low=527478210
./bitvisor-2.0/boot/login-simple/bitvisor.conf.tmpl:storage.conf0.lba_high=605602304
./bitvisor-2.0/boot/login-simple/bitvisor.conf.tmpl:storage.conf2.lba_high=1409024
./bitvisor-2.0/include/limits.h:#define UINT_MAX 4294967295u
./bitvisor-2.0/include/limits.h:#define ULLONG_MAX 18446744073709551615ULL
./bitvisor-2.0/edk/Foundation/Efi/Include/EfiApi.h:#if (EFI_SPECIFICATION_VERSION >= 0x0002000A)
./bitvisor-2.0/edk/Foundation/Efi/Include/EfiApi.h:#define EFI_RUNTIME_SERVICES_SIGNATURE  0x56524553544e5552
./bitvisor-2.0/edk/Foundation/Efi/Include/EfiApi.h:#define EFI_BOOT_SERVICES_SIGNATURE 0x56524553544f4f42
./bitvisor-2.0/edk/Foundation/Efi/Include/EfiApi.h:#define EFI_SYSTEM_TABLE_SIGNATURE      0x5453595320494249
./bitvisor-2.0/edk/Foundation/Efi/Protocol/SimpleTextIn/SimpleTextIn.h:    0x387477c1, 0x69c7, 0x11d2, 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b \
./bitvisor-2.0/edk/Foundation/Efi/Protocol/SimpleTextOut/SimpleTextOut.h:    0x387477c2, 0x69c7, 0x11d2, 0x8e, 0x39, 0x0, 0xa0, 0xc9, 0x69, 0x72, 0x3b \
./bitvisor-2.0/tools/dbgsh-uefi/dbgsh-uefi.c:   msg[0] = L"0123456789ABCDEF"[val & 0xF];
./bitvisor-2.0/core/constants.h:#define MSR_AMD_VM_CR                   0xC0010114
./bitvisor-2.0/core/constants.h:#define MSR_AMD_SYSCFG                  0xC0010010
./bitvisor-2.0/core/constants.h:#define MSR_AMD_TOP_MEM2                0xC001001D
./bitvisor-2.0/core/constants.h:#define MSR_AMD_VM_HSAVE_PA             0xC0010117
./bitvisor-2.0/core/svm_msr.c:  case 0xC0010020:        /* PATCH_LOADER MSR */
./bitvisor-2.0/core/svm_init.c:         /* passthrough writing to PATCH_LOADER MSR (0xC0010020) */
./bitvisor-2.0/core/printf.c:/* printf 20071010
./bitvisor-2.0/core/printf.c:           len = valconv (val, buf, sub10, "0123456789");
./bitvisor-2.0/core/printf.c:           len = valconv (val, buf, sub8, "01234567");
./bitvisor-2.0/core/printf.c:           len = valconv (val, buf, sub16, "0123456789ABCDEF");
./bitvisor-2.0/core/printf.c:           len = valconv (val, buf, sub16, "0123456789abcdef");
./bitvisor-2.0/core/beep.c:     counter2 = (2386364 / hz + 1) / 2;
./bitvisor-2.0/core/i386-stub.c: * $m0,10#2a               +$00010203040506070809101112131415#42
./bitvisor-2.0/core/i386-stub.c:static const char hexchars[]="0123456789abcdef";
./bitvisor-2.0/core/uefi.c:     static char SECTION_ENTRY_DATA hex[] = "0123456789ABCDEF";
./bitvisor-2.0/core/serial.c:#define RATELSB_115200             0x1
./bitvisor-2.0/core/serial.c:#define INIT_RATELSB               RATELSB_115200
./bitvisor-2.0/core/acpi.c:             tmp &= 16777215;
./bitvisor-2.0/core/io_iohook.c:                                i = IDMan_IPInitialize("123456789@ABCDEF",  &session);
./bitvisor-2.0/core/io_iohook.c:                                i = IDMan_generateSignatureByIndex( session, 1, "1234567890abcdef", strlen("1234567890abcdef"), sig, &siglen, 544);
./bitvisor-2.0/core/time.c:     oldtmr = oldnow & 16777215;
./bitvisor-2.0/core/time.c:                     tmr += 16777216;
./bitvisor-2.0/core/time.c:     mpudiv_128_32 (tmp, 3579545U, tmp); /* tmp = tmp / 3579545 */
./bitvisor-2.0/core/acpi_dsdt.c:static unsigned char buf[1048576];
./bitvisor-2.0/core/entry.s:    ## Processor check (241618J-019)
./bitvisor-2.0/core/entry.s:entry_pml4:                         #   7654321|76543210
./bitvisor-2.0/core/entry.s:entry_pd: # Page directory for PAE OFF      #   7654321|76543210
./bitvisor-2.0/core/tcg.c:#define TCPA 0x41504354
./bitvisor-2.0/core/vt_ept.c:                           tmp1 &= ~07777777;
./bitvisor-2.0/core/vt_ept.c:                           tmp2 |= 07777777;
./bitvisor-2.0/core/sleep.c:    while (usec > 3599591843U) {
./bitvisor-2.0/core/sleep.c:            usleep (3599591843U);
./bitvisor-2.0/core/sleep.c:            usec -= 3599591843U;
./bitvisor-2.0/core/svm_np.c:                           tmp1 &= ~07777777;
./bitvisor-2.0/core/svm_np.c:                           tmp2 |= 07777777;
./bitvisor-2.0/process/vpn.c:int heap[1048576], heaplen = 1048576;
./bitvisor-2.0/process/serialtest.c:            msgsendint (out, "@ABCDEFG1234567890\r\n"[i]);
./bitvisor-2.0/process/lib/lib_printf.c:/* printf 20071010
./bitvisor-2.0/process/lib/lib_printf.c:                len = valconv (val, buf, sub10, "0123456789");
./bitvisor-2.0/process/lib/lib_printf.c:                len = valconv (val, buf, sub8, "01234567");
./bitvisor-2.0/process/lib/lib_printf.c:                len = valconv (val, buf, sub16, "0123456789ABCDEF");
./bitvisor-2.0/process/lib/lib_printf.c:                len = valconv (val, buf, sub16, "0123456789abcdef");
./bitvisor-2.0/drivers/ieee1394log.c:   .device         = "class_code=060400,id="
./bitvisor-2.0/drivers/usb/usb_mscd.h:  /* 34567890123456789012345678901 */
./bitvisor-2.0/drivers/usb/usb_mscd.h:  /* 3456789012345 */
./bitvisor-2.0/drivers/usb/ehci_trans.c:        qh->epcap[0] = 0x40004000U;
./bitvisor-2.0/drivers/usb/usb.h:#define URB_STATUS_NAK          0x88U  /* 10001000 receive NAK (still active) */
./bitvisor-2.0/drivers/usb/usb.h:#define URB_STATUS_ERRORS       0x76U  /* 01110110 error */
./bitvisor-2.0/drivers/usb/usb.h:#define URB_STATUS_UNLINKED     0x7fU  /* 01111111 unlinked, ready to delete  */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x01000680U: /* GetDescriptor(DEVICE) */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x02000680U: /* GetDescriptor(CONFIG) */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x03000680U: /* GetDescriptor(STRING, langID) */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x03020680U: /* GetDescriptor(STRING, iProduct) */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x03010680U: /* GetDescriptor(STRING, iManufacturer) */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x22000681U: /* GetDescriptor(REPORT) */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x00010900U: /* SetConfiguration(1) */
./bitvisor-2.0/drivers/usb/usb_ccid.c:  case 0x02000921U: /* SetReport(Output Report) */
./bitvisor-2.0/drivers/pci_core.c:              if ((dev->config_space.class_code & 0xFFFF00) == 0x060400) {
./bitvisor-2.0/drivers/pci_init.c:      if ((dev->config_space.class_code & 0xFFFF00) == 0x060400) {
./bitvisor-2.0/drivers/ata/ata_init.c:  .device         = "class_code=010601",
./bitvisor-2.0/drivers/net/pro1000.c:           *tipg = 0x00702008;
./bitvisor-2.0/drivers/net/pro1000.c:                   /* 31608004.pdf */
./bitvisor-2.0/drivers/net/bnx.c:       bnx_mmiowrite32 (bnx, 0x6800, 0x00136034); /* Enable Send BDs. */
./bitvisor-2.0/drivers/net/bnx.c:       bnx_mmiowrite32 (bnx, 0x468, 0x2700142);
./bitvisor-2.0/drivers/net/bnx.c:       bnx_mmiowrite32 (bnx, 0x44C, 0x20209000);
./bitvisor-2.0/defconfig.tmpl:                  .lba_high =     12851999ULL,
./bitvisor-2.0/defconfig.tmpl:                  .lba_high =     1409024ULL,
```

出てきた行の周辺のコードのいくつかを取り上げて見てみます．

```c:core/time.c
bool
get_acpi_time (u64 *r)
{
	u32 tmr, oldtmr;
	u64 now, tmp[2], oldnow;

	VAR_IS_INITIALIZED (oldnow);
	asm_lock_cmpxchgq (&lastacpitime, &oldnow, oldnow);
	if (!get_acpi_time_raw (&tmr))
		return false;
	oldtmr = oldnow & 16777215;
	now = oldnow;
	if (tmr != oldtmr) {
		if (tmr < oldtmr)
			tmr += 16777216;
		now += tmr - oldtmr;
		asm_lock_cmpxchgq (&lastacpitime, &oldnow, now);
	}
	mpumul_64_64 (now, 1000000ULL, tmp); /* tmp = now * 1000000 */
	mpudiv_128_32 (tmp, 3579545U, tmp); /* tmp = tmp / 3579545 */
	*r = tmp[0];
	return true;
}
```

この16777215は何でしょうか？ 2の24乗マイナス1ですね．
https://ja.wikipedia.org/wiki/16777216
65536や1048576に比べるとなじみが薄い気がしますが，経験豊富なプログラマはこの定数を暗記しているのかもしれません．

では，3579545は？ ググるとすぐわかりますが，ACPI Power Management Timer の周波数3.579545 MHzです．
https://wiki.osdev.org/Timer_Interrupt_Sources#ACPI_Power_Management_Timer

こんな行もあります．

```c:vpn/lib/Se/SeKernel.c
ret = (UINT64)tick + (UINT64)rt->TickRoundCounter * 4294967296ULL;
```

4294967296は2の32乗ですね．この定数は一目見てわかる人も多そうな気がします．

次の関数ではビジーループでスリープを実現しています．

```c:core/sleep.c
/* busyloop for usec microseconds */
void
usleep (u32 usec)
{
	u32 count, remainder, counter0, tmp, diff;
	u64 acpitime, acpitime2;

	if (get_acpi_time (&acpitime)) {
		while (get_acpi_time (&acpitime2))
			if (acpitime2 - acpitime >= usec)
				return;
	}
	while (usec > 3599591843U) {
		usleep (3599591843U);
		usec -= 3599591843U;
	}
	asm_mul_and_div (14318181, usec, 12000000, &count, &remainder);
	if (remainder >= 12000000 / 2)
		count++;
	counter0 = get_timer0 ();
	while (count) {
		do
			tmp = get_timer0 ();
		while (counter0 == tmp);
		if (counter0 > tmp) {
			diff = counter0 - tmp;
			if (count < tmp)
				diff = count;
		} else {
			diff = 1;
		}
		count -= diff;
		counter0 = tmp;
	}
}
```

別のマジックナンバーが出てきました．3599591843 は何でしょうか？
これがマイクロ秒単位での時間だとすると，1時間すなわち3600000000マイクロ秒に0.4秒くらい足りません．
これは1時間を表すことを意図した値だが，PIT の分解能や数値計算の精度の理由で3600000000よりは少し小さい値になっている，とかではないかと推測していますが，よく調べてません．TSC やPIT などの時間関連ハードウェアは1マイクロ秒とか1ナノ秒とかの人間にとって切りのいい幅で時間を刻んではくれないので，人間にとって切りのいい時間を測ろうとすると誤差が出ることがあります．

14318181は水晶発振子の周波数14.318181 MHz ですね．
https://wiki.osdev.org/Programmable_Interval_Timer
https://jp.rs-online.com/web/p/crystal-units/1441065/

12000000は何を意味するのか？ 水晶発振子の周波数にスリープ時間（マイクロ秒）を掛け算して12000000で割っている理由は何か？
PITの周波数は1.19318166666... MHz ですが，これは水晶発振子の周波数の1/12です（NTSC のカラーサブキャリア周波数の1/3でもあります）．
1.1931817 * 1000000 * 12 = 14318180.4なので計算が合います．上記の計算により，スリープ時間中に刻まれる PIT のカウント数が求まります．

次．

```c:core/beep.c
void
beep_set_freq (unsigned int hz)
{
	unsigned int counter2;
	u8 l, h;

	counter2 = (2386364 / hz + 1) / 2;
	conv16to8 ((u16)counter2, &l, &h);
	asm_outb (PIT_CONTROL,
		  PIT_CONTROL_BINARY |
		  PIT_CONTROL_MODE3 |
		  PIT_CONTROL_16BIT |
		  PIT_CONTROL_COUNTER2);
	asm_outb (PIT_COUNTER2, l);
	asm_outb (PIT_COUNTER2, h);
}
```

2386364は何か？ PIT の周波数である約1193182のちょうど2倍の値です．

BitVisor のソースコード中には時間関係のマジックナンバーが多いですが，他の種類のマジックナンバーもあります．

```c:boot/login/minios_init/usbmem.c
void cbw_scsi_read_sector(cbw_packet* packet, int lba, int sectorSize, int sectorCount)
{
	packet->signature = 0x43425355;
	packet->tag = -40;
	packet->dataTransferLength = sectorSize;
	packet->flags = 0x80;										// read data will flow in
	packet->comLength = 10;									// scsi command of size

	// SCSI Command Packet
	packet->comData[0] = 0x28;								// read operation code
	packet->comData[1] = 0;								
	packet->comData[2] = (lba & 0xFF000000) >> 24;		// lba 1 (MSB)
	packet->comData[3] = (lba & 0xFF0000) >> 16;			// lba 2
	packet->comData[4] = (lba & 0xFF00) >> 8;			// lba 3
	packet->comData[5] = (lba & 0xFF);						// lba 4 (LSB)
	packet->comData[6] = 0;									// Reserved
	packet->comData[7] = (sectorCount & 0xFF00) >> 8;	// Transfer length MSB
	packet->comData[8] = (sectorCount & 0xFF);			// Transfer length LSB
	packet->comData[9] = 0;									// control
}
```

0x43425355とは？ USB Command Block Wrapper (CBW) のマジックナンバーですね．0x43, 0x42, 0x53, 0x55 がそれぞれ 'C', 'B', 'S', 'U' のアスキーコードです．

私は最近BitVisorでゲストOSの時間の流れをいじるという試みをやっているので，このへんのマジックナンバーに興味を持ったりしていました，
「BitVisorによるOSの見かけ上10倍速実行」大山恵弘（筑波大学）[スライド](https://www.bitvisor.org/summit7/slides/bitvisor-summit-7-4-oyama.pdf)
BitVisor Summit 7: https://bitvisor.connpass.com/event/100573/

これだけだとなんなので，grep 遊びをしている間にみつけたことをあと2つ．

コメントの中によく書かれている FIXME という文字列で grep してみます．

```
bitvisor-2.0$ grep -r FIXME . | wc -l
184
```

結構な行数が，自分を直してくれって言ってます．やばそうなコメントもありますが大丈夫でしょうか．．．（おせっかい）

あと，UTF-8 の文字コードのファイル（おそらく日本語を含むファイル）を探してみます．

```
bitvisor-2.0$ find . -type f -exec file '{}' \; | grep UTF-8 | wc -l
89
```

89ファイルありますね．海外の人が BitVisor のソースコードを読んだり編集したりするときのことが気になりました（さらにおせっかい）

今回はマジックナンバーを取り上げましたが，実は BitVisor のソースコードには謎のマジックナンバーはあまり多くは出てきません．
BitVisor のソースコードは他のソフトウェアと比べてきれいだと思います．