Skip to content

Instantly share code, notes, and snippets.

@orimanabu
Last active August 30, 2024 17:39
Show Gist options
  • Save orimanabu/603918eb335de9c6b1bcb8fa54cee0f7 to your computer and use it in GitHub Desktop.
Save orimanabu/603918eb335de9c6b1bcb8fa54cee0f7 to your computer and use it in GitHub Desktop.
Rosettaがやっている実行環境のチェック方法を確認する

(最新版はこちらをご覧ください: https://zenn.dev/orimanabu/articles/rosetta-libkrun)

はじめに

Appleは、Linux用のRosettaバイナリを提供しています。 これを使うと、Apple Silicon上のmacOS上で稼働するaarch64 Linux仮想マシン上で、x86_64バイナリを実行できるようになります1

Rosettaは、実行環境がVirtualization.framework(Apple純正のVMM用フレームワーク)を使った仮想環境かをチェックしており、そうでなければ実行できないらしく、 そのチェックは「rosettaバイナリに謎のioctl(2)を発行して、特定の文字列が返ってくること」を確認しているようです2

以下、その様子を再現してみたメモです。

環境

  • ホスト: Macbook Air M2, macOS, UTM
  • ゲスト: Fedora 40

手順

環境確認

ori@myfedora:~/work$ sudo dmidecode | head -n 15
# dmidecode 3.6
Getting SMBIOS data from sysfs.
SMBIOS 3.3.0 present.
Table at 0x16FCB3000.

Handle 0x0000, DMI type 1, 27 bytes
System Information
	Manufacturer: Apple Inc.
	Product Name: Apple Virtualization Generic Platform
	Version: 1
	Serial Number: Virtualization-c4e505cf-ced1-493f-9d6f-f5e46434e9d0
	UUID: cf05e5c4-d1ce-3f49-9d6f-f5e46434e9d0
	Wake-up Type: Power Switch
	SKU Number: Not Specified
	Family: Not Specified
ori@myfedora:~/work$ uname -r
6.8.5-301.fc40.aarch64

Rosettaを使えるようにする

ori@myfedora:~/work$ sudo mount -t virtiofs rosetta /mnt/rosetta
ori@myfedora:~/work$ findmnt /mnt/rosetta
TARGET       SOURCE  FSTYPE   OPTIONS
/mnt/rosetta rosetta virtiofs rw,relatime,seclabel
ori@myfedora:~/work$ ls -l /mnt/rosetta
total 436
-rwxr-xr-x. 1 ori ori 1660888 May 22 08:09 rosetta
-rwxr-xr-x. 1 ori ori  298680 May 22 08:09 rosettad

straceしてみる

ori@myfedora:~/work$ strace /mnt/rosetta/rosetta
execve("/mnt/rosetta/rosetta", ["/mnt/rosetta/rosetta"], 0xfffff242ddf0 /* 31 vars */) = 0
openat(AT_FDCWD, "/proc/self/exe", O_RDONLY) = 3
ioctl(3, _IOC(_IOC_READ, 0x61, 0x22, 0x45), 0xffffc32340e8) = 1
close(3)                                = 0
gettid()                                = 29760
write(2, "Usage: rosetta <x86_64 ELF to ru"..., 165Usage: rosetta <x86_64 ELF to run>

Optional environment variables:
ROSETTA_DEBUGSERVER_PORT    wait for a debugger connection on given port

version: Rosetta-318.8
) = 165
exit(1)                                 = ?
+++ exited with 1 +++

/proc/self/exe に謎のioctl(2)を発行しているのがわかる。

ioctl(2)の発行

straceの出力と[2]に載っているコードを参考に、下記のような a.c を作成する。

/* usage: `./a.out PATH_TO_ROSETTA_BINARY` */
/* see also: https://threedots.ovh/blog/2022/06/quick-look-at-rosetta-on-linux/ */

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <sys/ioctl.h>

#define KEY_SIZE 0x45

int main(int argc, char *argv[])
{
	if (argc != 2) {
		fprintf(stderr, "usage: %s path\n", argv[0]);
		exit(1);
	}

	int fd = openat(AT_FDCWD, argv[1], 0);
	if (fd < 0) {
		perror("openat");
		exit(1);
	}

	char key[KEY_SIZE];
	int result = ioctl(fd, _IOC(_IOC_READ, 0x61, 0x22, KEY_SIZE), key);
	if (result < 0) {
		perror("ioctl");
		exit(1);
	}

	printf("%s\n", key);

	exit(0);
}
ori@myfedora:~/work$ gcc a.c

実行すると...謎の文字列が返ってきた!

ori@myfedora:~/work$ ./a.out /mnt/rosetta/rosetta
Our hard work
by these words guarded
please don't steal
© Apple Inc

余談

libkrunはVirtualization.frameworkを使わないVMMだけど、このioctlの動きをエミュレート?することでRosettaサポートを導入した3。すごい。

libkrunの場合は、仮想マシンが上記のioctl(2)を発行したことを補足すると、ハンドラ内で ${HOME}/.krunvm-rosetta に書いた内容を返します。 したがって、あらかじめこのファイルを手で作って、ioctl(2)で返すべき文字列を書いておく必要があります。

...と思いきや、いろいろあって(virtiofs周りで)、いつのまにか使えなくなっていた4。残念。

Footnotes

  1. https://developer.apple.com/documentation/virtualization/running_intel_binaries_in_linux_vms_with_rosetta

  2. https://threedots.ovh/blog/2022/06/quick-look-at-rosetta-on-linux/

  3. https://github.com/containers/libkrun/pull/88

  4. https://github.com/containers/libkrun/pull/176/commits/6c2b9289b6a39826c9505f2fad5b04cc83982165

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment