
2026/04/12 5:58
アップルシリコンと仮想マシン:VM の台数制限(2)を超える方法(2023 年)
RSS: https://news.ycombinator.com/rss
要約▶
Japanese Translation:
主要なポイントは、Apple Silicon Mac が macOS Ventura ソフトウェア契約条項に組み込まれた閉源的な XNU カーネルによって実施される正式な 2 VM の制限を回避できることです。これは、カスタム開発用カーネルをインストールすることで可能となり、特定のブート引数(
hypervisor= および hv_apple_isa_vm_quota)を使用することにより、最大 255 つの同時仮想マシンを動作させることが可能です。成功するには、Mac をシャットダウンし、リカバリモードで起動し、システム完全性保護(SIP)を無効にし、kmutil を使用してカスタムカーネルコレクションを作成および設定する必要があります。検証は sysctl kern.osbuildconfig を使用し、NVRAM のブート引数をチェックすることで実施できます。
しかし、このカスタマイズには重大なトレードオフが伴います。ユーザーは簡素化された OS アップデートを失い、後で変更を取り戻すために
bputil によるポリシーリセットの手動管理が必要となります。著者は M2 Pro MacBook Pro で macOS VM を 9 つ実行し、副作用として熱発生とファンの作動が確認したことでこの方法を成功裏にテストしました。大規模な開発環境では技術的に実装可能ではありますが、プロセスには高度な専門知識が必要です。特に recoveryOS テルミナルを通じてブートポリシーを扱う技能が必要で、コアセキュリティプロトコルを損なうことなくシステム安定性を維持する必要があります。本文
macOS 内部機構の深層分析:開発用カーネルコレクションの構築
概要
過去数ヶ月間、OpenCore Legacy Patcher(OCLP)以外で何をしていたか気になっていた皆様へ。私は地元のコンサルタント企業にて、Mac Admin インターンとして素晴らしい機会を得て働きました。
私が特に多く携わっていた分野の一つが、macOS の仮想マシン環境です。具体的には、Apple が提供する仮想化フレームワークをベースにした Apple Silicon 搭載の仮想マシンです。しかし、U TM という優れたプロジェクトを通じて Apple の仮想化スタックを使って開発・テストを継続する中で、非常に不便と感じる制限事項に突き当たりました:Apple Silicon のホストマシンの場合、同時にアクティブな macOS ゲスト仮想マシンの数が最大で 2 台に限られているという点です。
これは主に以下のようなエラーメッセージが
Virtualization.framework から発生することで確認できます:
The number of virtual machines exceeds the limit. The maximum supported number of active virtual machines has been reached. VZError.Code.virtualMachineLimitExceeded
その制限について
このエラーが発生する主な理由は、**macOS のソフトウェア利用規約(SLA)**の第 2.B.iii 条に規定されています:
(iii) お持ちおよび管理されている Apple ブランドのコンピュータ上で、現在 Apple Software を実行している際、Apple Software およびそれ以前の macOS または OS X オペレーティングシステムソフトウェア、またはその後の Apple Software リリースの追加コピーまたはインスタンスを最大 2 つ(2)まで、仮想オペレーティングシステム環境上でインストールし、使用して実行することを目的とする場合: (a) ソフトウェア開発のために;(b) ソフトウェア開発中のテストのために;(c) macOS Server の利用のために;または (d) 個人的・非商用の目的のための利用。
業務上、単一マシン上で Apple が正式に許可する macOS のコピーを同時に仮想化して使用する数は 2 を超えることはできませんが、私は依然として、Apple がこのチェックを macOS のどの箇所に実装しているのか、そして愛好家や研究者たちが 2 つ以上アクティブな macOS 仮想マシンの同時実行を可能にする方法を探索することに興味を持っていました。
調査:macOS 内部機構の深層分析
当初、私はこの制限事項がユーザーランド(ユーザー空間)ベースのものであると考え、その理由は
/System/Library/Frameworks/Virtualization.framework のどこかに埋め込まれているのではないかと考えました。macOS Big Sur における dyld のフレームワーク統合を考慮すると、フレームワークを手作業で抽出するか、Hopper Disassembler などのツールを使用して dyld shared cache に埋め込まれた特定のバイナリを読み込む必要がありました。
これにより、フレームワークの詳細な検討が可能になりました。しかし、数時間の調査を行っても、Apple が仮想マシンの制限をどこに実装しているかを見つけることはできませんでした。せいぜい、エラーメッセージ自体はフレームワークから発生するものだが、ユーザーランドそのものでは Apple がハードコーディングされた「2 つの仮想マシン」という制限を定義していないだけだということを確認できたにとどまりました…
Hack Different Discord サーバーで
jevinskie さんからいただいたヒントにより、Apple のゲストマシンの制限は、閉鎖ソースである XNU(macOS カーネル)内の何らかの箇所に実装されていることを学びました。Intel ベースのカーネルには同じコードはないことはわかっていましたが、Intel カーネルと Apple Silicon カーネルの関数および文字列を比較することに時間をかけると、メインの仮想化スタックは hv_vm_* の元にあることが分かりました。
macOS Sonoma Beta 4 (23A5301h) の開発用カーネルを IDA に投入すると、仮想化スタックの初期化コードである
hv_init() が発見されました。
開発用カーネルを取得するには、開発者ポータルから該当 OS の Kernel Debug Kit をダウンロードする必要があります。
ここで Apple が仮想マシンの制限処理を行っている様子が伺えます:
hv_apple_isa_vm_quota 変数を int 型として使用し、新しい仮想マシンが起動/停止するごとにこの変数を減算・加算しています。
| 関数タイプ | 関数名 |
|---|---|
| 増分関数 | |
| 減分関数 | |
また、興味深いことに2 つの新しいブート引数が存在します:
hypervisor= および hv_apple_isa_vm_quota=。
- 前者は後者のための単なるゲートチェックであり、後者はさらに興味深いです。
はカーネル内の仮想マシンの制限を上書きできるのです!hv_apple_isa_vm_quota=
しかし、さらに調査を行うと、このロジックはリリース版のカーネルでは同一ではないことが分かりました。代わりに、Apple は hypervisor のブート引数を System Integrity Protection (SIP) を通じた AppleInternal チェックに置き換えていると考えられます:
SIP に関するさらなる情報については、こちらの記事を参照してください:System Integrity Protection
/* CSR_ALLOW_APPLE_INTERNAL = 0x10 XNU ソースからの抜粋: #define CSR_ALLOW_APPLE_INTERNAL (1 << 4) https://opensource.apple.com/source/xnu/xnu-7195.121.3/bsd/sys/csr.h.auto.html */ if ((*(int8_t *)_csr_config & 0x10) != 0x0) { _PE_parse_boot_argn_internal(*0xfffffe00072696d0 + 0x6c, "hv_apple_isa_vm_quota", 0xfffffe0007b58410, 0x4, 0x0); }
ここでは 2 つの選択肢があります:
- Apple の開発用カーネルを起動する。
- リリース版カーネルを修正して、AppleInternal チェックを除去する。
私が残りのメンタルヘルスを保つために、第 1 の選択肢を選ぶことにしました。そのため、次の課題はマックブックプロ上で開発用カーネルを起動することです。
開発用カーネルコレクションの構築
開発用カーネルコレクションを構築するには、Apple の開発者サイトから適切な Kernel Debug Kit (KDK) を入手する必要があります。KDK はホストマシンの種類と一致させておくことが必須であり、そうでないとカーネルおよび kext のリンキング時、また起動時に問題が発生します。
KDK ディスクイメージをダウンロードし、埋め込まれたパッケージをインストールしたら、お使いの Mac が使用しているカーネルの種類を確認してください:
uname -v | awk -F '/' '{print $NF}' | awk -F '_' '{print $NF}'
**M2 Pro搭載のマックブックプロ (Mac14,9)**の場合、これは
T6020 を返します。M1 と M2 等不同な世代のような他の CPU モデルでは、カーネルのバリエーションが異なるため注意してください:
これでカーネルの構築を開始できます!
以下の呼び出しは前提としており、以下を想定しています:
- ホストマシンのカーネルは T6020 を使用していること。
- ホストが macOS 14.0, ビルド 23A5301h を実行していること。
下記のアプローチを、それぞれお使いのホストに合わせて調整してください。
Apple のエンジニアチーム、特に Jeremy C. Andrus氏への感謝です。カスタムカーネル起動に関するブログ投稿はこちら:Building XNU for macOS 11.2 (Intel + Apple Silicon)
sudo kmutil create \ --arch arm64e \ --no-authorization \ --variant-suffix development \ --new boot \ --boot-path VirtualMachine.kc \ --kernel /Library/Developer/KDKs/KDK_14.0_23A5301h.kdk/System/Library/Kernels/kernel.development.t6020 \ --repository /Library/Developer/KDKs/KDK_14.0_23A5301h.kdk/System/Library/Extensions \ --repository /System/Library/Extensions \ --repository /System/Library/DriverExtensions \ --explicit-only $(kmutil inspect -V release --no-header | grep -v "SEPHiber" | awk '{print " -b "$1; }')
このコマンドにより、ホームディレクトリに
VirtualMachine.kc ファイルが作成されます。パスを覚えておいてください。後で recoveryOS からこのファイルにアクセスする必要があります。
マックの開発用カーネルコレクションの起動設定
最後に、Mac をシャットダウンし、電源ボタンを長押しして **"Option"**を選択することで recovery モードへの起動を行います:
次に、ユーザーを認証し、メニューバーから Utilities -> Terminal を選択してください。ここでマシンのいくつかの設定ポリシーを設定します:
- System Integrity Protection(SIP)を無効化。
- カスタムブート引数の渡与を許可する。
- Mac の起動用カスタムカーネルコレクションを設定する(
をお使いのボリュームに置き換えてください)。Macintosh HD - ブート引数を設定する:
: 起動するカーネルコレクションのバリエーションを設定します。kcsuffix=
: Virtualization Stack の特殊機能を有効にします(特に VM クォータの上書き機能)。hypervisor=
: VM クォータを上書きします。最大値はhv_apple_isa_vm_quota=
ですが、実用性を考慮して0x7FFFFFFF
(255 台)に設定しています。0xFF
csrutil disable bputil --disable-boot-args-restriction kmutil configure-boot --volume "/Volumes/Macintosh HD" --custom-boot-object "/Volumes/Macintosh HD/Users/*/VirtualMachine.kc" nvram 40A0DDD2-77F8-4392-B4A3-1E7304206516:boot-args='kcsuffix=development hypervisor=0x1 hv_apple_isa_vm_quota=0xFF'
再ブート後、ターミナルでこれが適用されているか確認できます:
sysctl kern.osbuildconfig nvram boot-args
マシンを運用開始!
これで準備が整いました。次に、
Virtualization.framework を利用する仮想化ソリューションを取得してください。例としては:
- UTM
- Viable
- Parallels
これで仮想マシンの起動が可能になります!以下に示すように、私の M2 Pro搭載のマックブックプロでは9 台の macOS 仮想マシンを同時に動作させることができました。テスト用途には引き続き利用可能です!
(これは私が初めてこのマシンのファンが作動したときでもあり、コストパフォーマンスに満足しています ;p)
Apple がこの機能を提供したのはいつ?
macOS 12 (Monterey) の登場に伴い、Apple は Virtualization スタックの側にこのブート引数を追加したようです。さらに、Sonoma のカーネルでお見かけしたように、Monterey でもまだ AppleInternal チェックが存在しています。XNU にはまだたくさんの秘密が隠されているようですね。
OS アップデート時の作業復元について
Apple Silicon でカスタムカーネルコレクションを使用する場合、いくつかの不幸なデメリットがあります。最大のデメリットは、ストリーミングされた OS アップデートが利用できなくなる点です。アップデートをインストールすることは依然可能です。しかし、アップデート完了後にマシンでエラーが発生します。
これを修正するには、マシンのストックカーネルコレクションに戻す必要があります。
復元するには、recoveryOS で
bputil を使用して新しいブートポリシーを作成するだけで済みます。完全なセキュリティ(--full-security)またはその他の組み合わせ(例:--disable-boot-args-restriction)いずれでも構いません。このコマンドを recoveryOS で実行し再起動すると、ストックカーネルが有効になります。
考察
全体として、これは非常に興味深い調査の旅となりました。Apple がどのようにこの制限を実装しているか理解できたことに感謝しています。さらに、この使用ケースが公式にはサポートされていないにもかかわらず、CoreOS の仮想化チームが愛好家に対してこの制限を上書きするオプションを提供してくれたことにも心から敬意を表します(文書化されてはいないし、簡単ではありませんが)。
今後の向上策として考えているものですが、実装は非現実的です:
- KC の構築と起動を自動化するツールの開発。
- 指定されたホスト用に開発用カーネルコレクションをダウンロードおよび生成。
- recoveryOS でホストの構成を変更し、カーネルコレクションから起動するように設定。
変数を上書きできるカーネルエクステンションの開発を検討。hv_apple_isa_vm_quota- カスタム開発用カーネルコレクションの必要性を排除。
いずれにせよ、コミュニティがこの記事に興味を持っていただければ幸いです。次なる旅では、Apple Silicon 仮想マシンにおける DEP レジスター/シリアル番号の上書きが可能かを探求したいと考えています。ただし、今回の成功ほどラッキーになれるとは限りません ;p