HN 日本語サマリー

← 一覧へ戻る
プログラミング

Greg Kurtzer's Ginux はユーザー空間カーネルになった

Greg Kurtzer's Ginux is now a userspace kernel (github.com)

110 pointsby d3Xt3r70 コメント

要約

Ginux は、当初独立した Rust カーネルとして開発されていましたが、現在はホスト Linux カーネルと管理対象ワークロードの間に明示的な契約を提供するユーザー空間カーネルへと方向転換しました。この変更により、AI エージェントの封じ込めや、Human-Directed Agentic Engineering (HDAE) メソッドを活用した開発実験がより効果的に行えるようになります。

全文翻訳

Ginux

Ginux は、分離された Linux 互換インスタンスのための設定可能なユーザー空間カーネルです。 通常の Linux プロセスとして実行され、管理対象ワークロードとホストカーネルの間に、明示的でバージョン管理された契約を配置します。

重要

Ginux は、UEFI を介して直接ブートし、Rocky Linux 10 のユーザー空間を実行する独立した Rust カーネルとして始まりました。その研究フェーズは完了しました。最終的なソースコードは、bootable-kernel ブランチと bootable-kernel-final タグに永久に保存されています。アクティブな開発は、ユーザー空間カーネルとしてここ(現在のリポジトリ)で継続されています。

プロジェクトが方向転換した理由

スタンドアロンカーネルの実験は、経験豊富な人間がアーキテクチャ、ゲート、実行可能テストを通じて指示した AI コーディングエージェントが、意味のある Linux ユーザー空間を実行できる新しいカーネルを構築できることを証明しました。また、その結果の限界も明らかになりました。

Linux はソースコード以上のものです。それは、安定したインターフェース、開発プロセス、グローバルコミュニティ、ベンダーとハードウェアの連携、そして数十年にわたる互換性と運用経験です。カーネルメカニズムを再実装しても、そのエコシステムを再現することはできませんし、Linux と競合することが目標であったこともありません。

より有用な結果は、実験によって露呈された境界です。Linux は広範なユーザー空間 ABI を維持しなければなりません。Linus Torvalds が言ったように、「そして私たちはユーザー空間を壊しません。」カーネル回帰ドキュメントはその規則を記録しています。Ginux は Linux の上に配置され、各管理インスタンスに意図的に小さな契約を提供できます。管理対象のシステムコールがホストに影響を与える前に、Ginux はそれをエミュレートするか、検証済みの仲介操作を実行するか、拒否するかを決定します。

率直に言って、Linux はユーザー空間を壊してはなりません。Ginux は、意図的かつ選択的に完全な Linux ABI 保証を壊すように設計されています。 インスタンスは、承認されたワークロードが必要とする機能とインターフェースの動作のみを受け取ります。すべての逸脱は、偶発的な非互換性ではなく、明示的で、バージョン管理され、レビュー可能で、テストされることを意図しています。

このピボットは、開発方法論の結果でもあります。AI により、使い捨て可能でありながら実行可能なプロトタイプコードを構築し、アーキテクチャのアイデアをテストし、実行中のシステムから学び、価値のある部分をより良い設計に引き継ぐことが実用的になりました。プロトタイプは証拠であり、すべての実験を製品に変える義務ではありませんでした。

現在の Ginux

ホスト Linux カーネル
  `- ホスト systemd (実際の PID 1)
       `- ginux (通常の信頼されたホストプロセス)
            `- インスタンス契約
                 |- 仮想プロセスとID
                 |- 仮想ディスクリプタとカーネルビュー
                 |- 割り当てられたデバイスとリソース
                 `- 管理対象 Rocky Linux ユーザー空間
                      `- インスタンス systemd (仮想 PID 1)

Ginux はネイティブの x86-64 プログラムを監視し、ホストへの影響の前に管理対象システムコールをインターセプトします。中央ディスパッチャはインスタンス契約を解決し、3つの結果のいずれかを選択します。

  • エミュレート: Ginux 所有の状態から完全に回答する。
  • 仲介: リクエストを検証および翻訳し、狭い Ginux 所有のホスト操作を実行する。
  • 拒否: 設定された Linux 互換のエラーを返すか、タスクを終了する。

現在の実装には以下が含まれます。

  • セキュリティ重視の x86-64 インタープリタとバランスの取れたネイティブ ptrace バックエンド。
  • 厳格でバージョン管理されたインスタンス設定とライフサイクル。
  • ダイジェストピン留めされた OCI ルート、不変ファイルシステムインデックス、およびバウンドオーバーレイ。
  • Ginux 所有のプロセス、認証情報、シグナル、同期、タイマー、イベントモデル。
  • 明示的な割り当て、所有権、および取り消しを備えた仮想デバイス。
  • バウンドされた仮想 /proc、/sys、cgroup v2、マウント、ネームスペース、マシン、およびブートIDビュー。
  • システムコールによって引き続き仲介されるホスト共有ネットワークバックエンド。
  • multi-user.target に到達し、管理コンソールログインを認証し、Rocky の有効なリポジトリを通じて更新し、インスタンスをクリーンにシャットダウンするピン留めされた Rocky Linux 10 systemd ベースライン。

これは名前付きの互換性ベースラインであり、完全な Linux または systemd 互換性を主張するものではありません。その正確なイメージ、準備完了マーカー、テスト、証拠、および制限は、hdae/gates-todo/9-systemd-baseline.md に記録されています。

エージェント封じ込め研究

Ginux は、コマンドを実行し、ファイルを変更し、ネットワーク接続を開き、追加のプロセスを開始できる AI エージェントやその他の自動化ソフトウェアの封じ込め境界としてもテストされています。エージェントにホストの完全な Linux ABI を提供する代わりに、オペレーターは、タスクに必要な操作と仮想リソースのみを公開するカーネル契約を持つインスタンス内にそのプロセスツリーを配置できます。

研究目標は、システムコール、ioctl、ファイルシステム、デバイス、ネットワーク、プロセス権限、および仮想 /proc と /sys 状態にまたがるレビュー可能な境界です。たとえば、契約により、エージェントは時間を読み取り、自身のプロセスを検査し、割り当てられた 1 つのワークスペースを変更できますが、クロック変更、ホストファイルシステムアクセス、未承認のネットワークリスナー、および無関係なデバイスは拒否されます。Ginux は、エージェントとその子プロセスが実行中に契約の決定を監査できます。

これはアクティブな検証ターゲットであり、Ginux が現在プロダクショングレードのエージェントサンドボックスであることを主張するものではありません。契約インベントリ、設定可能なポリシー、敵対的テスト、パフォーマンスコスト、およびエスケープ境界は HDAE ゲートを通じて追跡され、より強力な封じ込め主張が行われる前に実証される必要があります。

他のシステムとの関係

ユーザー空間カーネルというアイデアは、確立された研究およびエンジニアリング分野です。Ginux は、その設計空間における特定の点を探索しています。

アプローチ主な境界強調の違い
Linux seccompホストシステムコールをフィルタリングする既存の ABI を制限するのではなく、完全な仮想契約を定義する
User-Mode LinuxLinux をホストプロセスとして実行する仮想ハードウェア上で完全な Linux カーネルを再利用する
gVisorユーザー空間でアプリケーションカーネルを実装する互換性とパフォーマンスの目標が異なる、密接に関連するモデル
GramineアプリケーションをライブラリOSでパッケージ化するマニフェストとライブラリOS境界を使用する
ProxosプライベートOSとコモディティOS間で呼び出しをルーティングするシステムコールインターフェース全体で信頼の配置を設定可能にする
Ginux各インスタンスにバージョン管理されたカーネル契約を与える宣言された契約、仮想状態、デバイス、リソース、ライフサイクルを 1 つのレビュー可能な境界として扱う

Ginux は完全な Linux ABI を約束しません。互換性主張は、名前付きの契約、ワークロード、および実行可能証拠にのみ適用されます。

開発とテスト

参照開発環境は macOS arm64 です。QEMU TCG は、Rocky Linux 10 x86-64 ホストをピン留めしてブートし、Ginux は通常の非特権プロセスとして実行されます。ホスト systemd は実際の PID 1 のままです。

前提条件を確認してください。

make doctor

明示的なネットワーク操作を使用して、ピン留めされたアセットを準備します。

make host-image-fetch
make image-helper-fetch
make instance-image-fetch
make systemd-image-fetch

キャッシュがポピュレートされた後、オフラインで決定論的なスイートをビルドします。

make build
make check
make test

最新の完了した機能を直接検査します。

make test-systemd       # キャッシュされたイメージ、外部ネットワーク無効
make bench-prepare      # ピン留めされたベンチマークイメージのワンタイムネットワーク設定
make bench              # マッチしたネイティブ/Ginux マトリックスと必須の予算チェック
make bench-modes-prepare # 3方向ディスパッチ比較のワンタイム設定
make bench-modes        # ネイティブ/選択的/パラノイドテーブルとグラフ
make demo-gate-15       # バウンドされた再現可能な3方向比較
make test-systemd-live  # 共有ネットワークと実際のアップストリーム dnf -y update
make host-run           # Ginux がインストールされた一般的なインタラクティブ Rocky ホスト
make host-reset         # そのホストのキャッシュ、インスタンス、書き込み可能状態を破棄
make demo-gate-9        # 同じホストワークフローを通じたゲート 9 チェックポイント

インスタンスレシピは [contract.syscalls] の下でシステムコール制御を選択します。

[contract.syscalls]
control = "selective" # デフォルト; すべてのシステムコール仲介には "paranoid" を使用
default = "deny"
allow = ["*"]
deny = []

selective はデフォルトであり、インスタンス契約が操作を許可し、Ginux のバージョン管理されたカタログがそれを直接安全と分類した場合にのみ、直接ホスト実行を許可します。拒否、仮想状態、検査、翻訳、エミュレーション、ポインタまたはディスクリプタ検証、および変更された結果は、両方のモードで Ginux ディスパッチのままです。paranoid は明示的なオプトインであり、完了前にすべてのシステムコールを Ginux ユーザー空間ディスパッチャに送信します。

make bench-compare は、4% のネイティブ予算に対して各行をチェックし、benchmarks/gate11/ の下に受け入れられたベースラインが公開された後、その Ginux ベースラインに対してもチェックします。環境の不一致は、パフォーマンスの回帰とは別に報告されます。make demo-gate-11 は、バウンドされた人間が検査可能な比較を実行し、必須の行が予算を達成できなかった場合に非ゼロを返します。

ゲート 15 は、ネイティブ Rocky、選択的 Ginux、およびパラノイド Ginux を横断する個別の特性評価ワークフローを提供します。ネイティブは仲介なしの制御であり、Ginux インスタンスモードではありません。benchmarks/gate15/ の下のチェックインされたテンプレートは、完全なテストプロトコルを修正し、スクリプトを編集せずにコピーできます。make bench-modes は、build/gate15/ の下にペアになった生サンプル、メタデータ、Markdown テーブル、および SVG グラフを生成します。正確なプロトコル、カスタマイズワークフロー、出力スキーマ、および解釈の制限については、再現可能なパフォーマンス測定 を参照してください。

make host-run は QEMU Rocky ホストをブートし、その通常のシェルにログインさせます。Ginux は PATH にインストールされています。最初の create または import は、ピン留めされた Rocky OCI イメージをライブのレイヤーごとの進行状況でダウンロードおよび検証します。後続の操作はキャッシュを再利用します。書き込み可能な Rocky ホストオーバーレイは、make host-run、通常のクリーンアップ、ビルド、およびテスト全体で永続化されるため、キャッシュされたイメージ、インスタンス定義、ルート、および停止状態が利用可能になります。make host-reset は、ホストを停止し、そのオーバーレイを削除する明示的な破壊操作です。次の make host-run は、ピン留めされたクリーンな Rocky イメージから開始します。完全な最初のセッションは次のとおりです。

ginux create rocky
ginux list
ginux status rocky
ginux start rocky --attach

create は、文書化されたデフォルトレシピから開始します。ginux import NAME FILE を使用して、自己完結型レシピからインスタンスを作成またはアトミックに置き換えます。ginux export NAME はそのレシピを出力し、ginux edit NAME はエディタセッションを検証してアトミックに適用します。

インスタンスはデフォルトで契約ロックされています。明示的なメンテナンスウィンドウの場合、インスタンスを停止し、ginux unlock NAME を実行し、必要なメンテナンスを実行し、再度停止してから ginux lock NAME を実行します。ginux list と ginux status NAME は現在の状態を示し、ロックされていないインスタンスを開始すると警告が表示されます。アンロックは設定可能なレシピ制限のみを緩和します。Ginux は依然として仮想カーネル境界を所有し、サポートされていない権限を拒否し、ホストIDを削減し、NoNewPrivs を適用します。ロック状態はホストのデプロイメント状態であり、エクスポートされたポータブルレシピには決して書き込まれません。

システムコール監査は [audit] enabled = false でデフォルトで無効になっています。その実行で監査を有効にするには ginux start に --audit を追加するか、すべての開始に対して有効にするには enabled = true を設定します。有効な監査レコードは常にインスタンスの audit.log に送信されます。それらはアタッチされたコンソールから分離されています。既存の mode = "stderr" または mode = "disabled" を使用するレシピは読み取り互換性のままですが、書き直されると新しいブール形式に正規化されます。

インスタンス仕様は、型付きレシピオーバーライド、イングレスおよびエグレス契約ポリシー、ボリューム、仮想ID、および順序付けされたブート前フックをサポートします。ホストネットワークアタッチメントと翻訳されたポートはデプロイメント設定であり、インスタンスが作成または変更されたときに繰り返し可能なフラグとして提供されます。

ginux import web /etc/ginux/examples/rocky-systemd.toml \
    --network eth0:1 \
    --forward protocol=tcp,external_port=8080,instance_port=80 \
    --forward protocol=tcp,external_port=8443,instance_port=443
ginux set web \
    --network default \
    --forward none

--network を省略すると、ホストのデフォルトネットワークが使用されます。複数のフラグは検証され、アトミックに永続化されます。無効な組み合わせは何も変更しません。フックは仲介されたインスタンスプロセスとしてのみ実行され、Ginux は任意のホストコンテキストフックをサポートしません。スキーマ、優先順位ルール、例、および検証ターゲットについては、ゲート 9.75 インスタンス仕様 を参照してください。

同じインスタンスファイルには、[contract] およびその syscalls、filesystem、network、devices、privileges、process、kernel サブセクションの下に自己完結型の階層契約が含まれています。システムコール名は、ピン留めされたカタログに対してコンパイルされたバウンドされたグロブを受け入れます。明示的な拒否が常に優先されます。契約は、個別のオペレーターオブジェクトではなく、インスタンスの一部です。起動前に完全なインスタンスレシピを検証および検査します。

ginux validate /etc/ginux/examples/rocky-systemd.toml
ginux inspect /etc/ginux/examples/rocky-systemd.toml
ginux explain /etc/ginux/examples/rocky-systemd.toml filesystem.path.write

構文、優先順位、移行動作、および完全な CLI ワークフローについては、自己完結型ユーザー空間契約 を参照してください。

アタッチされた端末は Ginux インスタンスコンソールになります。root としてパスワード ginux でログインし、通常どおり探索し、Ctrl-] を押してインスタンスを実行したままデタッチし、インスタンスルートとして kill -RTMIN+4 1 を実行して systemd をシャットダウンし、ホストに戻ります。デタッチされた操作では ginux start rocky、ginux status rocky、ginux stop rocky を使用します。Rocky ホストシェルを終了すると QEMU がクリーンに停止します。これにより、永続的なオーバーレイを削除せずに VM が停止します。make clean はそのホスト状態をリセットします。make demo-gate-9 は同じオペレーターワークフローを使用します。make run-systemd は互換性エイリアスとして残っており、make test-systemd-interactive は自動化された回帰テストです。

ライブテストとインタラクティブデモは、共有外部ネットワークを有効にします。管理対象のすべてのシステムコールがインターセプトおよび監査されるため、QEMU TCG 下でのアップストリーム DNF アップデートには数分かかる場合があります。オフライン systemd テストは、準備されたダイジェストピン留めキャッシュのみを使用します。

個々のコンポーネントとゲートターゲットは、Makefile および docs/ および hdae/ の下の対応するファイルに文書化されています。

セキュリティモデルと制限事項

主な敵対者は、インスタンス内のプロセスを制御します。ホストカーネル、ハードウェア、Ginux 実行可能ファイルと承認済み設定、ブートチェーン、およびオペレーターは現在信頼されています。バランスの取れたネイティブバックエンドは、ELF ロード、アドレス空間、ページフォールト、シグナル、スケジューリング、および ptrace についてホストに依存しており、これらはホストカーネルの攻撃対象領域のままです。

Ginux は研究ソフトウェアです。独立したセキュリティ認証を受けておらず、完全な Linux 互換性を提供せず、プロダクションワークロードの準備ができていません。未知の契約操作はクローズドで失敗しますが、現在のカバレッジと保証はテスト済みのゲートに限定されています。

正確なサポートされる主張、保持されたスーパーバイザー権限、信頼されたコンポーネント、除外事項、互換性のギャップ、パフォーマンスの制限、および再現可能な境界テストは、セキュリティ境界と制限事項 に文書化されています。

エージェント封じ込めの場合、保護されるオブジェクトはホストであり、明示的にインスタンスに割り当てられていないすべての権限です。Ginux は、エージェントとそのツールが実行される Linux プロセスを制約します。モデルの推論を検査したり、外部モデルプロバイダーを保護したり、強制されたインスタンス境界外で信頼されていないコードを安全にしたりするものではありません。

完全な意図、脅威モデル、不変条件、およびゲート計画は以下にあります。

開発方法

Ginux は Human-Directed Agentic Engineering (HDAE) で開発されています。人間が所有する製品の意図、アーキテクチャ、制約、および受け入れ境界と、エージェントが実行する実装、診断、およびテストループを組み合わせています。承認された各ゲートは、そのスコープ、非目標、受け入れ基準、検証、証拠、および停止点を hdae/ に記録します。

歴史的なスタンドアロンカーネル

独立したブート可能カーネルは、研究および歴史的参照のために引き続き利用可能です。

これはもはやアクティブな開発ラインではありません。コードは、リポジトリの既存の条件の下で、独立して研究またはフォークすることを選択する人々に利用可能です。

名前は Linux と同じファミリーのジョークのままです。Ginux は Linux、GPT、および Greg を組み合わせたものです。作者の自尊心を構成済みリソース制限内に保つために、G は公式には GPT を表します。

ライセンス

Ginux は Apache License 2.0 の下で利用可能です。LICENSE および NOTICE を参照してください。

設定済みネイティブ起動

x86-64 Linux 上で、ginux launch <config> <root> [--result-file <fresh host path>] は、指定されたホストルートディレクトリ内で、設定された引数と環境で [instance].init を実行します。ブートストラップには chroot および認証情報変更権限、および close_range (Linux 5.9 以降) を持つカーネルが必要です。ワークロードを実行する前に UID/GID 1000 にドロップします。設定は profile = "balanced" および backend = "ptrace-native" を選択する必要があります。ストレージとデバイスの割り当てはこのコマンドでは実装されておらず、拒否されます。

[instance].workdir はオプションで、デフォルトは /work です。/ もサポートされています。ブートストラップは、親ディレクトリが存在する場合に作業ディレクトリを作成し、権限をドロップした後にそこに入ります。Init および作業ディレクトリのパスは 128 バイトに制限され、.. パスコンポーネントを含まない絶対パスである必要があります。最大 7 つの 128 バイトの引数と、最大 8 つの 256 バイトの NAME=value 環境エントリが受け入れられます。無効または大きすぎる入力は、起動前に失敗します。

ワークロードの標準出力は、標準エラー出力上のスーパーバイザー診断から分離されます。標準入力、標準出力、標準エラー出力のみがワークロードに継承されます。ランチャーはワークロードの終了コード、またはシグナル終了の場合は 128 + signal を返します。起動失敗は 2、スーパービジョンまたは結果書き込み失敗は 1 を返します。ネイティブの fork、clone、および後続の exec はサポートされておらず、子スーパービジョンが実装されるまで fork は ENOSYS を返します。非 x86-64 システムコール ABI およびジョブ制御グループ停止は明示的に失敗します。監査出力は 64 KiB プラス切り捨て通知に制限されます。このパスはインスタンスメタデータからのリソースクォータを実装しません。

要求された場合、結果ファイルは起動前に排他的に予約され、モード 0600、最大パス長 512 バイトです。既存のファイルは上書きされません。完了後、1 つの同期された JSON オブジェクトが含まれます。

{"version":1,"outcome":"exited","code":0,"signal":null,"generation":null}

outcome は exited、signaled、または supervisor-error です。関連する code または signal のみが入力されます。ストレージ世代は実装されていないため、generation は null です。結果の欠落、空、または形式が不正な場合はプロトコルエラーです。結果の書き込み、同期、またはクローズの失敗は、ワークロードが成功した場合でも 1 を返します。コンシューマーは、読み取る前にランチャーの完了を待つ必要があります。

フォーカスされた Linux 統合シナリオは、既存のバイナリを使用します。

make build
make build-launch-fixture
make build-gate1-fixture
sudo make test-gate1-setup
sudo make test-launch
sudo make test-native-supervision

ネイティブプロセスシナリオ

別の process-native <config> <executable> コマンドは、ネイティブの fork、clone、vfork、exec、スレッド、wait、終了シグナル、およびパイプを処理します。呼び出し元として信頼されたホストフィクスチャを実行し、chroot なしで実行します。子プロセスをトレースできるホストでは root は必要ありません。設定された launch は個別のエントリポイントであり、このプロセスループはまだ使用していません。

プロセス作成は、clone TID セルを含む仮想 ID を返します。トレースされていない、再親化された、ネームスペース化された、およびサポートされていない clone フラグは拒否されます。スレッドスロットは終了時に再利用されます。CLONE_FILES は 1 つのディスクリプタテーブルを共有します。通常の fork はそれをコピーし、exec はそれを共有解除してから CLOEXEC エントリを閉じます。ワーカー スレッドの exec はグループのプロセス ID を保持します。標準エラー出力より上のホストファイルは、実行前に閉じられます。PI futex 操作および他のタスクの堅牢リストのクエリはサポートされていません。

フィクスチャを明示的にビルドし、それらの独立したシナリオを実行します。

make build build-process-fixtures
make test-process-native
make test-process-native SCENARIO=shared_pipe
make test-process-native SCENARIO=thread_exec

シナリオは .artifacts/process の下の既存のバイナリを使用し、システムコール ABI ディスパッチ、clone 制限、ディスクリプタ継承、スレッド再利用、成功および失敗したワーカー exec、シグナル、wait ステータス書き込み、ノンブロッキング wait、および vfork のチェックが含まれます。既存のネイティブ fork フィクスチャも実行されます。これらのチェックは、完全な libc、ジョブ制御、または systemd 互換性を主張するものではありません。