Sandboxing Script Extensions with GraalVM

原文はこちら。
The original article was written by Christian Humer (Consulting Researcher, Oracle).
https://medium.com/graalvm/sandboxing-script-extensions-with-graalvm-f192a8fb0c5f

アプリケーションでは、顧客から提供されたスクリプト、動的に読み込まれるスクリプト、あるいはAIによって生成されたスクリプトを実行するケースが増えています。本記事では、GraalVMのサンドボックス機能を活用して、これらのスクリプトがアクセスできる範囲を制限し、消費するリソースを制限し、ホストアプリケーションから障害を隔離する方法について解説します。

次のような方に本記事をお勧めします。

  • スクリプト拡張システムを開発している方。
  • サーバー上で顧客から提供されたスクリプトを実行している方。
  • アプリケーションやAIモデルがスクリプトを生成している場合。
  • JavaScriptやWebAssemblyを埋め込んでおり、そのコードや入力を信頼できない場合。

JavaScriptの割引ルール(discount rule)を具体例として用い、信頼できるアプリケーションコードから完全に信頼できないソースへと段階を追って解説します。このアプローチは、ホストがJVM上で動作する場合でも、Native Imageでビルドされたネイティブ実行ファイルとして動作する場合でも同様に有効です。

Why script extensions need sandboxing

モダンなSaaSアプリケーションでは、すべての顧客に単一の固定ワークフローを強制するのではなく、組織がビジネスロジックをカスタマイズできるようにすることがよくあります。あらゆるビジネスモデル、統合、ポリシーを予測できる製品は存在しないため、拡張性は採用の重要なドライバーです。ビジネスアプリケーションのカスタマイズを軸に、業界全体が成長してきました。

カスタム拡張機能は、アプリケーションが意図的に開放している動作を補完します。アプリケーションは、拡張機能が受け取るデータ、呼び出せる操作、および返さなければならない結果を定義します。拡張機能は、欠けている意思決定、変換、またはワークフローを補完します。製品がすでに実装している動作を選択する設定とは異なり、スクリプト拡張機能は、製品開発者が想定していなかったロジックを表現できます。

拡張機能は、多くの場合、実行時に評価される小さなスクリプトの形式をとります。スクリプトは、アプリケーションを再ビルドすることなく読み込んだり変更したりできるため、特に便利です。

アプリケーションが拡張コードの実行を開始すると、信頼され、十分に監査されたコードから、多かれ少なかれ未知の領域へと境界を越えることになります。拡張コードには、意図しない無限ループが含まれていたり、過剰なメモリを割り当てたり、悪意のある入力を処理したり、あるいは意図的にランタイムを攻撃したりする可能性があります。

ここで説明した機能はすべて、Oracle GraalVM および GraalVM Community Edition の両方で利用可能です。

A discount rule extension

この記事では、Orderを受け取り、割引率を返す割引ルール拡張を使用します。必要なのは注文総額のみであるため、Orderは単一のメソッドのみを公開しています:

public final class Order {

    private final double total;

    public Order(double total) {
        this.total = total;
    }

    @HostAccess.Export
    public double total() {
        return total;
    }
}

このアプリケーションで維持されるルールは、次のようなものになるでしょう。

Source rule = Source.create("js", """
                (order) => {
                    if (order.total() >= 100) {
                        return 0.10;
                    }
                    return 0.0;
                }
                """);

try (Context context = Context.newBuilder("js").build()) {
    Value discount = context.eval(rule);
    double rate = discount.execute(new Order(120)).asDouble();
    System.out.println(rate);
}

このフローは4つの部分で構成されています。Sourceは、その実行とは独立して拡張コードを表します。Contextには、ゲストアプリケーションの状態と設定が含まれます。context.eval(rule)は、そのコンテキスト内でソースを評価し、JavaScript関数を表すValueを返します。execute()を呼び出すと、エクスポートされたOrderを使用してその関数が呼び出されます。

同じSourceは複数のコンテキストで評価することができ、各評価によって、そのコンテキストが所有するValueが生成されます。

サンドボックスポリシーが指定されていないため、コンテキストはTRUSTEDを使用します。JavaとJavaScriptは同じランタイムで実行され、同じヒープを共有するため、相互運用性のオーバーヘッドが最小限に抑えられ、共同最適化が可能になります。

ソースと入力が信頼されているアプリケーション所有のルールについては、これが適切なトレードオフとなるかもしれません。しかし、すべての拡張機能がすべてのホスト機能にアクセスしたり、アプリケーションとリソースを共有したりできるべきではありません。GraalVM を使用すれば、ルールの表現、評価、実行方法を変更せずに、こうした境界を追加できます。まずは、拡張機能がアクセスできる範囲を制限することから始めます。

Constraining host access

割引ルールには注文合計額が必要ですが、ホスト環境からのその他の情報は一切必要としません。通常の Context は、最初から制限の厳しいデフォルト設定で開始します。つまり、明示的にエクスポートされたホストメンバーにのみアクセス可能であり、ネイティブアクセス、プロセス作成、環境へのアクセス、およびホストのファイルやソケットへのアクセスは無効になっています。

TRUSTEDでは、これらの制限はデフォルトとして設定されており、アプリケーションコードはコンテキストの設定時にこれらの制限を緩和することができます。CONSTRAINEDは制限の厳しい設定を強制し、共有設定コードやその後のリファクタリングによって導入されたものを含め、互換性のないオプションを拒否します。

try (Context context = Context.newBuilder("js")
                .sandbox(SandboxPolicy.CONSTRAINED)
                .out(OutputStream.nullOutputStream())
                .err(OutputStream.nullOutputStream())
                .build()) {
    Value discount = context.eval(rule);
    double rate = discount.execute(new Order(120)).asDouble();
    System.out.println(rate);
}

Order.total()は、@HostAccess.Exportで明示的にマークされているため、引き続き利用可能です。その他のホストメソッドやクラスは自動的に公開されません。jsと指定しているので、コンテキストがJavaScriptに限定されます。制約付きコンテキストでは、許可される言語のリストを明示的に指定する必要があります。

このポリシーにより、最終的な構成において、広範なホストアクセス、ネイティブアクセス、プロセスの作成、システムからの終了、ホストファイルやソケット、継承された環境変数、ホストクラスの読み込みの有効化を防ぎます。アプリケーションのいずれかの部分が互換性のない機能を要求した場合、コンテキストの作成は失敗します。ポリシーが暗黙のうちに緩和されることはありません。

CONSTRAINED では、ゲストの出力ストリームとエラーストリームを明示的に指定する必要があります。この例では、両方を破棄しています。ゲストの出力を保持するアプリケーションは、境界が定められた、アプリケーションが所有するストリームを使用する必要があります。最後の System.out.println はホストアプリケーションのコードであり、このリダイレクトの影響を受けません。

公開範囲は意図的に狭く設定されています。

エクスポートされたメソッドはすべて、アプリケーション定義の機能を保持しています。もしOrderrefund()cancel()を公開している場合、スクリプトはそれらを呼び出せます。エクスポートされたメソッドは、ゲストの入力に対して検証を行う必要があり、特権操作を公開してはいけません。サンドボックスは、危険なアプリケーション操作を安全なものにできません。

CONSTRAINEDは、拡張機能に対するアプリケーションコードの公開範囲を制限しますが、JavaとJavaScriptは依然として基盤となるランタイムリソースを共有しています。CPUやメモリの使用量を制限するには、さらに高度なレベルのサンドボックス化が必要です。

Running trusted code on untrusted input

この時点で、ホストへのアクセスが限定された信頼できるルールには、これ以上の安全対策は必要ないと考えがちです。しかし、「信頼できるソース」は「信頼できる入力」を意味するわけではありません。ルールを変更できない攻撃者であっても、そのルールを最悪の挙動に追い込むようなデータを選択できます。ホストへのアクセス制限は、過度なCPU使用、メモリ割り当て、あるいはゲストランタイムの障害を防御できません。

本番環境のルールは、クーポンの解析、明細項目のトラバース、入れ子になったメタデータの検査などを行う場合があります。巧妙に作成されたクーポンは最悪のケースの解析パスを引き起こし、巨大な注文は多量の一時領域の割り当てを招き、予期しない数値はループを、作成者が不可能だと想定していた状態に陥らせる可能性があります。不正な形式の入力は、ゲスト言語のライブラリやランタイムの欠陥を露呈することさえあります。

ISOLATEDにより、これら両方の懸念に対処できます。CONSTRAINEDの機能制限を強制することに加え、CPUおよびアイソレート・ヒープの制限を課し、ゲストコードを、独自のヒープ、ガベージコレクタ、およびJITコンパイラを備えた独立したランタイムインスタンスで実行します。

隔離実行には、Mavenの言語依存関係のisolateバリアントが必要です。JavaScriptの場合は、Oracle GraalVMではjs-isolateを、GraalVM Community Editionではjs-isolate-communityを使用してください。依存関係の詳細については、Polyglot Isolatesの構成を参照してください。

Polyglot Isolates – Embedding Languages

try (Context context = Context.newBuilder("js")
.sandbox(SandboxPolicy.ISOLATED)
.out(OutputStream.nullOutputStream())
.err(OutputStream.nullOutputStream())
.option("engine.MaxIsolateMemory", "64MB")
.option("sandbox.MaxCPUTime", "2s")
.build()) {
Value discount = context.eval(rule);
double rate = discount.execute(new Order(120)).asDouble();
System.out.println(rate);
}

ソース、評価、および呼び出しを変更する必要はありません。上記のメモリおよびCPUの制限は、ISOLATEDコンテキストの作成において必須であり、いずれかが省略されるとコンテキストの作成が失敗します。これらの値はアプリケーション側で設定する必要があります。CPUに依存する実行は、設定予算を超過すると中止しますが、ゲストによる割り当てはアイソレート・ヒープに対して計上されます。

サンドボックスの設定は、以下のように変更されました。

Separate VM and heap, but still inside the same OS process.(VMとヒープを分離するが、同一OSプロセス内のまま)

デフォルトでは、ゲストランタイムはアプリケーションプロセス内でアイソレートとして実行されます。また、独立したアドレス空間やプロセス境界が必要な場合は、外部プロセスとしての実行も可能です。このデプロイメントの選択肢については、後で改めて取り上げます。

Java APIの外観は変わりませんが、ヒープが分離されているため、JavaとJavaScriptの間を行き来する参照のライフサイクルが変化します。これが、次に考慮すべき影響です。

Working with separate heaps

一見すると、別々のヒープがあることでメモリの所有権が単純化されるように思えます。つまり、ホストオブジェクトは一方のヒープに、ゲストオブジェクトは別のヒープに存在します。しかし、ヒープ間の参照によって、その構図は複雑になります。

別々のヒープを設けることで、ゲストの実行環境には独自のガベージコレクタが割り当てられ、メモリの領域管理に明確な境界が生まれます。JavaとJavaScriptがヒープを共有する場合、それぞれのオブジェクトは同じメモリプールを占有します。GraalVMはコンテキストが保持するメモリ量を推定できますが、その計測は定期的に行われるものであり、制限適用前に上限を超過してしまう可能性があります。また、ゲスト専用のヒープに対して絶対的な上限を設定することもできません。

アイソレート(isolate)はこの状況を変えます。engine.MaxIsolateMemoryオプションは、ゲストランタイムのヒープ全体に絶対的な上限を設定します。ゲストによるメモリ割り当ては、ホストアプリケーションのヒープ領域を消費するのではなく、この上限に対して計上されます。これはアイソレート・ヒープに対する制限であり、ネイティブメモリやプロセスメモリのあらゆる形態に対する制限ではありません。

独立したヒープであっても、JavaとJavaScriptの間で値がやり取りされることを妨げるものではありません。オブジェクトは元のヒープに残りつつ、境界を越える参照は裏側でハンドルによって表現されます。これにより、分散ガベージコレクションでおなじみの問題が生じます。

割引ルールが、割引が適用された理由を記録するためのDiscountLogコールバックも受け取ると仮定します。

public final class DiscountLog {

    private String reason;

    @HostAccess.Export
    public void report(Value details) {
        reason = details.getMember("reason").asString();
    }
}

JavaScript が log.report({ reason: "large order" }) を呼び出す際、details は Java に渡されるゲスト値です。実装では、必要なフィールドが Java の String にコピーされるため、ホスト側はゲストヒープへの参照を保持しません。

スコープ付きのコールバック値がない場合、detailsをJavaのフィールドに保持すると、ゲストオブジェクトがlogを参照し返している場合に、ヒープ間の循環参照が発生する可能性があります。この完全な循環参照はアプリケーションからはもはや到達不能になっているかもしれませんが、各ガベージコレクタは依然として他方のヒープからの参照を検知し、それぞれの側を存続させ続けてしまうでしょう。

Each collector sees an incoming reference from the other heap. Neither can determine that the cycle is dead.(各コレクタは、もう一方のヒープからの参照が流入していることを認識する。どちらのコレクタも、そのサイクルがデッドサイクルであることを判断できない)

分散ガベージコレクションの問題は、小規模なテストでは通常、保持されたオブジェクトが蓄積する前に終了してしまうため、また、各ヒープを個別に調べても明らかなリークが見られないため、見過ごされがちです。しかし、本番環境では、クロスヒープのサイクルが徐々に蓄積され、はるかに後になって、アイソレート・ヒープの肥大化、予期せぬリソース制限による障害、あるいはスループットの低下といった形で表面化することがあります。サイクルを生み出したコールバックは、最終的に現れる症状とはかけ離れた場所にある場合があり、そのため問題の診断が特に困難になります。

GraalVM は、エクスポートされた Java コールバックに渡されるゲスト側の値にスコープを限定することで、このサイクルのよくある偶発的な発生を回避しています。ISOLATEDはデフォルトでこの動作を有効にしており、次のセクションで説明する信頼できないソースに対するポリシーである UNTRUSTEDも同様です。ホストはコールバックの実行中にそのような値を使用できますが、コールバックが戻ると、ゲストヒープへの参照は解放されます:

While the callback runs, the host may use the guest value and copy what it needs.(コールバック実行中、ホストはゲストの値を使用し、必要なものをコピーできる)
The host keeps copied data, not a reference into the guest heap.(ホストはコピーしたデータを保持する。ゲストヒープへの参照ではない)

スコープ付きコールバックパラメータの場合、detailsreport()の実行中のみ有効です。コールバックが返ると、スコープ付きのValueは無効化され、ゲストヒープ内へのその参照は解放されます。これをJavaのフィールドに保持して後で使用すると、IllegalStateExceptionが発生します。

コールバックで意図的にゲスト値を保持する必要がある場合は、戻り値の返却前にdetails.pin()を呼び出しましょう。ピン留めを行うと、その値は自動解放の対象外になります。これは明示的なライフタイムの決定であり、2つのヒープ間に長寿命の参照が再導入される可能性があるため、慎重に使用する必要があります。

既存のOrder.total()コールバックはゲストオブジェクトを受け入れないため、特別な処理は必要ありません。

スコープ付きコールバックパラメータは、別々のヒープに移行する際にアプリケーションが考慮すべき主要な相互運用性のルールです。それ以外の場合、コンテキストの作成、評価、および値の呼び出しは以前と同様に機能します。

ホスト機能、ランタイム障害、およびヒープ間の参照が考慮されたことで、最後のステップ、ルールソース自体への信頼をやめることに進みましょう。

Running untrusted code

「信頼できないJavaScript」の最もよく知られた例は、Webブラウザです。ブラウザは、WebサイトからJavaScriptをダウンロードし、そのWebサイトが悪意のあるものである前提で実行します。スクリプトは、JavaScriptランタイムからの脱出を試みたり、JITコンパイラを悪用したり、リソースを枯渇させたり、利用可能なあらゆる機能を悪用したりする可能性があります。スクリプトは、ブラウザを侵害したり、ローカルマシンへの任意のアクセス権を取得したりしてはなりません。

UNTRUSTEDは、この敵対的モデルを想定して設計されています。この例では、顧客が提供した割引ルールがWebサイトのJavaScriptの役割を果たし、SaaSアプリケーションがブラウザの役割を果たします。

これまで、アプリケーションが割引ルールのソースを管理してきました。ここで、そのソースが顧客によって提出されたもの、外部データベースから読み込まれたもの、あるいはAIによって生成されたものであると仮定します。その場合、Source自体は、信頼できないものとして扱わなければなりません。

Source rule = Source.create("js", submittedRule);

Sourceインスタンスの作成とは、単に提示されたプログラムを表すだけに過ぎまず、プログラムの妥当性を検証したり、そのプログラムを信頼できるものと見なしたりするものではありません。サンドボックスは、適切に構成されたコンテキストでソースが評価される際に確立されます。API では許可されている場合でも、UNTRUSTED以外のポリシーで信頼できないソースを実行することはサポートされておらず、サンドボックスの対象外です。

ISOLATEDでは、ルールを信頼し、バグや悪意のある入力からホストを保護していました。UNTRUSTEDでは、攻撃者がパーサー、ランタイム、およびJITコンパイラによって処理されるソースを制御します。攻撃者は、リソースを消費したり、異常なランタイムパスを実行させたり、コンパイラによって生成されるマシンコードを操作したりするプログラムを意図的に構築できます。

UNTRUSTEDは、ISOLATEDで提供される独立したランタイム、ヒープ、ガベージコレクタ、およびJITコンパイラをそのまま使います。さらに、追加のリソース制限を課し、敵対的なゲストコードに対処するために設計されたコンパイラおよびランタイムの防御機能を有効にします。

double applyDiscount(Source rule, Order order) {
    try (Context context = Context.newBuilder("js")
                    .sandbox(SandboxPolicy.UNTRUSTED)
                    .out(OutputStream.nullOutputStream())
                    .err(OutputStream.nullOutputStream())
                    .option("engine.MaxIsolateMemory", "64MB")
                    .option("sandbox.MaxHeapMemory", "32MB")
                    .option("sandbox.MaxCPUTime", "2s")
                    .option("sandbox.MaxASTDepth", "100")
                    .option("sandbox.MaxThreads", "1")
                    .option("sandbox.MaxOutputStreamSize", "64KB")
                    .option("sandbox.MaxErrorStreamSize", "64KB")
                    .build()) {
        Value discount = context.eval(rule);
        return discount.execute(order).asDouble();
    }
}

ISOLATEDと同様に、UNTRUSTEDの実行は、ランタイムが設定されたCPUの予算超過を検出した後にキャンセルされます。GraalVMは、isResourceExhausted()trueを返すPolyglotExceptionを発生させて、この失敗を報告します。リソース制限によってコンテキストがキャンセルされると、そのコンテキストではゲストコードを実行できなくなります。

攻撃者が制御するソースコードにより、JITコンパイラも攻撃対象領域の一部になります。UNTRUSTEDは、生成されたマシンコードに埋め込まれた定数を不可視にして、コンパイル済み関数のエントリポイントをランダム化することで、JITスプレー攻撃に対してコンパイラの出力を予測しにくくします。

Look Ma, no constants | Proceedings of the 15th European Workshop on Systems Security

また、メモリアクセスをマスキングし、マスキングが適用できない箇所には投機的実行バリアを挿入します。

Monocle: Transient Execution Proof Memory Views for Runtime Compiled Code | Proceedings of the 20th ACM Asia Conference on Computer and Communications Security

ゲストには独自のJITコンパイラがあるため、これらの防御策をゲストコードに適用しても、ホストアプリケーションのコンパイラに負荷をかけることはありません。

最後に残された仮定が1つあります。実行が正常にサンドボックス内に封じ込められた場合、その結果は信頼できると考えるかもしれませんが、実際にはそうではありません。悪意のあるルールは、サンドボックスから一度も脱出しずに-1NaN、または1000を返す可能性があります。アプリケーションは、割引率が有限であり、0から1の範囲内であることを検証する必要があります。サンドボックスはルールの実行方法を制限しますが、その回答が意味をなすかどうかを決定するものではありません。

ISOLATEDおよびUNTRUSTEDの両モードにおいて、ゲストランタイムはデフォルトでアプリケーションプロセス内の内部アイソレートとして実行されます。独立したアドレス空間とプロセス境界を必要とするアプリケーションは、engine.IsolateMode=externalを使用して外部アイソレートモードを利用できます。子プロセスは独立したアドレス空間とシグナルドメインを持つため、ゲストの致命的な障害によってホストプロセスが終了することはなくなります。

この例のサンドボックスの制限値は、実稼働時のデフォルト値ではなく、あくまで参考例です。実稼働時の制限値は、代表的なワークロードに基づいて決定する必要があります。sandbox.TraceLimitsの使用を含め、サンドボックスのリソース制限の設定を参照してください。

Resource Limits – Sandboxing

ポリシーとその制限値を選択したら、次はどのスクリプトがエンジンを共有できるかを決定します。

Sharing code within a security domain

SaaSアプリケーションが、1人の顧客に対して1つのルールを実行することはめったにありません。リクエストやテナントをまたいだ多くの実行コンテキストで、同じルールやライブラリが実行される場合があります。コンテキストごとに個別のエンジンを作成すると、そのコードを不必要に繰り返し解析したりウォームアップしたりする必要があるからです。

明示的なEngineは、コード共有の範囲を定義します。これはコードキャッシュ(キャッシュされたSourceエントリ、解析済みのAST、プロファイリングデータ、および最適化されたマシンコード)を管理します。Contextは、グローバル変数、ゲストオブジェクト、モジュール、およびコンテキストに紐付けられたValueインスタンスを含む、実行スコープのアプリケーション状態を所有します。エンジンの共有はコードの共有であり、アプリケーション状態の共有ではありません。

デフォルトでは、各コンテキストは暗黙的なエンジンを作成します。アプリケーションは、セキュリティドメインに対して明示的なエンジンを作成し、Context.newBuilder("js").engine(domainEngine)を使用してそれを各コンテキストに渡し、共有を有効にします。エンジンは、ドメインで許可された言語、サンドボックスポリシー、デフォルトのストリーム、およびengine.MaxIsolateMemoryなどのエンジンレベルのオプションを指定して作成する必要があります。それに紐付けられたコンテキストは、互換性のあるサンドボックス設定を使用する必要があります。これにより、ソースを一度解析するだけで済み、コンパイルやウォームアップのコストをコンテキスト間で分散させることができます。これにより、多数のコンテキストが同じコードを実行する際の起動遅延やメモリ使用量を削減できます。

Graal.js を含む Truffle 言語は、コンテキスト非依存のコードを実装しています。これはつまり、同じ JavaScript AST および最適化されたマシンコードが、最初にそれを実行したコンテキストのグローバル変数やオブジェクトをキャプチャしなくても、異なるコンテキストで実行できる、ということです。これには、ピークパフォーマンスにおいてわずかなオーバーヘッドが伴います。つまり、型チェック、プロパティへのアクセス、および関数やメソッドの呼び出しは、コンテキスト固有のオブジェクト識別子に対してそれほど積極的に特化できなくなるからです。同じコードが多くのコンテキストで実行される場合、繰り返し行われる構文解析やウォームアップを回避できるメリットは、通常、そのコストを上回ります。

セキュリティドメインとは、アプリケーションがコードアーティファクトや実行時リソースの共有を許可するゲストプログラムのグループのことです。同じドメイン内のプログラムは、ホストに対してすべて信頼できないものとみなされる場合でも、相互に不信感を抱く必要はありません。たとえば、ある顧客のルールはエンジンを共有できる一方で、互いに隔離する必要がある顧客のルールは別々のエンジンを使用します。

エンジンを共有するすべてのコンテキストは、そのエンジンのサンドボックスポリシーを使用します。isolate-backed実行では、ゲストランタイム、アイソレートヒープ、ガベージコレクタ、およびJITコンパイラも共有されます。したがって、engine.MaxIsolateMemoryのハードリミットは、ドメインの共有アイソレートに適用されます。コンテキストごとの制限はコンテキストごとに適用され、通常はそのコンテキスト内のゲスト実行間で累積されます。異なるセキュリティドメインのスクリプトには、個別のエンジンが必要です。

Bringing sandboxed extensions to production

サンドボックス化は、GraalVMにとって長年にわたる重点分野です。その基盤となるPolyglot API、Truffleランタイム、GraalJSは、長年にわたり本番環境で利用されてきました。Oracle社内では、NetSuite SuiteScriptやOracle Database MLEが、これらの技術を長年にわたり活用しています。Picnic社もGraalVMを活用し、JavaバックエンドからJavaScriptおよびPythonのビジネスルールを実行しており、「PicnicにおけるPythonとJavaScriptによるJavaの拡張」で説明されているように、1日あたり約3,800万件のルールを評価しています。

Graal Runtime Technology Improves NetSuite Platform Developer Productivity | NetSuite
JavaScript in the Oracle Database

GraalVMは、JVMホストアプリケーションが、アプリケーションデータに近い場所でJavaScriptやWebAssemblyを実行し、ホストAPIを公開し、多くの独立したコンテキストで再利用可能なコードを実行する必要がある場合に適しています。これは、ホストがJVM上で動作する場合でも、Native Imageでビルドされたネイティブ実行ファイルとして動作する場合でも同様です。Native Imageビルドには、ネイティブホストリフレクションの設定で説明されているように、ゲストコードに公開されるホストメンバーへの到達可能性メタデータ (reachability metadata) を含める必要があります。

Configuring Native Host Reflection – Embedding Languages

GraalVMは、スクリプトがアプリケーション所有のコードから信頼できないユーザーによって送信されたソースコードまで多岐にわたる場合に特に有用です。これは、同じPolyglot APIが、段階的に強化された機能、リソース、および分離の境界をサポートしているためです。同じAPIを複数の言語で使用することも可能です。

GraalVM 25.1では、サンドボックスポリシーではJavaScriptおよびWebAssemblyをサポートしています。ネイティブ拡張機能のない純粋なPythonコードに対するサンドボックスサポートは現在開発中です。

GraalJS – JavaScript
GraalWasm
GraalPy

GraalVM Community Edition 25.1 では、これらのサンドボックス機能をより広範な GraalVM コミュニティに提供します。開発者の皆様がこれらの機能を活用して、サンドボックス化されたスクリプトを構築、評価、展開される様子を楽しみにしています。GitHub および GraalVM Community Slack を通じて、ユースケース、質問、フィードバックをお待ちしています。

Issues · oracle/graal · GitHub
Slack でgraalvmに参加する | Slack

まずは、embedding language、Polyglot Isolates、および サンドボックス に関するドキュメントをご覧ください。

Embedding Languages
Polyglot Isolates – Embedding Languages
Sandboxing

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください