3 ポイント 投稿者 GN⁺ 2024-07-31 | 1件のコメント | WhatsAppで共有
  • DARPAのTRACTORは、レガシーCコードをRustへ自動変換し、Cプログラムのメモリ安全性に関する脆弱性のカテゴリをなくすことを目指す研究プログラムである
  • CとC++のメモリ安全性の問題は20年以上にわたって扱われてきたが、バグ検出ツールだけでは十分でないという認識が形成されている
  • 代替策は、コンパイル時に安全でないプログラムを拒否する安全なプログラミング言語へ既存コードを移行することだ
  • 変換結果は、熟練したRust開発者が書いたコードと同等の品質とスタイルを目標とし、静的・動的解析と大規模言語モデルベースの機械学習を組み合わせる
  • MIT Lincoln Laboratoryが試験・評価を担当し、ベンチマーク、マイルストーンプロジェクト、ツールは公開ページに掲載されている

TRACTORの目標

  • TRACTORは「Translating All C to Rust」プログラムであり、レガシーCコードをRustへ自動変換することを目標とする
  • セキュリティの観点では、Cプログラムに存在するメモリ安全性に関するセキュリティ脆弱性のカテゴリ全体を取り除こうとしている
  • 変換されたコードは単に動作するだけでなく、熟練したRust開発者が作成したコードと同等の品質とスタイルを志向する

なぜRustへの変換が必要なのか

  • CとC++のメモリ安全性の問題は、ソフトウェアエンジニアリングコミュニティが20年以上にわたって取り組んできた課題である
  • バグ検出ツールのみに依存する方法では、問題を十分に解決するのは難しいという合意が形成されている
  • より好ましいアプローチは、コンパイル時に安全でないプログラムを拒否できる安全なプログラミング言語を使うことだ
  • TRACTORはその対象言語としてRustを採用している

自動変換に使われる技術

  • TRACTORは、レガシーCコードをRustへ移行するために、複数のソフトウェア解析技法と機械学習技法を組み合わせる
  • 解析技法

    • 静的解析動的解析をあわせて活用する
    • 大規模言語モデルを含む機械学習技法も組み合わせに含まれる
    • この組み合わせは、Cコードの構造と動作を把握し、Rustコードへ自動変換するために必要な中核技術群である

試験・評価と公開資料

1件のコメント

 
GN⁺ 2024-07-31
Hacker News のコメント
  • 参考までに、https://sam.gov/opp/1e45d648886b4e9ca91890285af77eb7/view も見る価値があります

    • 提案者向け説明会情報 PDF への直接リンク: https://sam.gov/api/prod/opps/v3/opportunities/resources/fil...
      このイベントの目的は、TRACTOR の技術目標と課題を説明し、潜在的な提案者からの質問に答え、それぞれの研究が TRACTOR プログラムの目標にどう合致するかを検討する機会を提供することだとされています
  • これは本当に難しそうです。特に熟練者が書く慣用的な Rustは C とはまったく似ておらず、興味深いコードの多くは C++ で書かれています
    結局のところ、C プログラムにおけるすべての割り当ての寿命を静的に判定するのと同じことではないかと思います。ユーザー定義アロケータやプロプライエタリなライブラリへ渡る割り当てまで含めてです。この分野の研究は長く続いてきましたが、大きな成功は多くありませんし、C/C++ プログラムでは参照カウントのような安全策がなくても、ユーザーがどのボタンを押すかに割り当ての寿命を結び付けることができます。良い考えではありませんが、可能ではあります
    もう一つの明らかな問題は、解析対象のプログラムが定義上バグのあるコードだという点です。寿命が筋の通ったものだったなら、メモリ安全性の脆弱性も存在せず、置き換える必要もなかったはずです。静的に「寿命がどうあるべきか」を検出する研究は、たいてい解析対象のコードがそもそも正しいことを前提にしています。寿命を判定できない箇所を見つけて、開発者に助けを求めるプログラムを目標にすることはできるかもしれません

    • 非常に難しい仕事で、DARPA は難しいことに資金を出すのが好きです[1]
      ただし DARPA が自動プログラム翻訳や Rust への自動翻訳を試みるのは今回が初めてではありません[2]
      [1]: https://www.urbandictionary.com/define.php?term=DARPA%20hard
      [2]: https://c2rust.com/
    • 難しい仕事の話で言えば、DOE も 20 年以上続いている ROSE というプロジェクトに資金提供しています。静的解析や C/C++/Cuda 間の自動翻訳はもちろん、Python のような高水準言語、HPC 向けの C/C++ 変種まで扱っています
      このプロジェクトは、こうした言語を実質的に同じノード型の集合でサポートする統合抽象構文木を持っていて、かなりクールです。2014 年夏に Livermore でインターンをしたときに作業する機会がありました
      オープンソースでもあります: http://rosecompiler.org/ROSE_HTML_Reference/index.html
    • 一般的なケースでは unsafe Rust に翻訳され、たまに孤立した末端ノードだけが安全な Rust に翻訳される、という形になりそうです
      借用チェッカーと格闘するだけでも難しいと感じるなら、C のあり得るすべてのプログラム空間と悪名高い未定義動作まで考慮して、借用チェッカーが承認するコードへ自動翻訳する作業ははるかに難しいです。コンパイラ作成における古典的な問題の一つは、有効なプログラムの空間が、コンパイル可能なプログラムの空間よりはるかに大きいということです
      ざっと検索したところ、c2rust のような試みもあります[1]。TRACTOR がどう違うのか気になります
      [1] https://github.com/immunant/c2rust
    • DARPA の課題が DARPA-hard と呼ばれるのには理由があります
    • アプローチはおそらく「AI がプログラムの機能を何らかの記述言語で要約し、同じ機能集合をカバーする Rust コードを合成する」といったものになりそうです
      元のプログラムを入れる代わりに、そのプログラムのマニュアルを入れる方式なら、より興味深いでしょう。ただし、マニュアルがプログラムの微妙な挙動をすべて含んでいることはまれなので、少なくとも実際の基準値を得るにはソースコードを覗く必要がある可能性が高いです
  • この提案されたイニシアチブのことはしばらく前から知っていたので、こうして公開されるのは興味深い。非常に野心的な提案であり、このくらいの野心はDARPAのミッションに合っていると思うので、うまくいってほしい。
    この分野でRustを支持する立場として、CからRustへの自動翻訳の可能性について、この提案を推進する人たちの期待値を下げようとしてきた。私が見る根本的な障害は、CのソースコードがRustのソースコードよりも情報量が少ないという点だ。CコードをRustコードに翻訳するには、誰か、あるいは何かが、その欠けている情報を作り出さなければならない。画像を大きく拡大しても、元画像に捉えられていない情報ビットを誤りなく作り出すことはできないのと同じ理由で、この欠けた情報を完全に生成することは不可能だと容易に証明できる。結局、既存のソースコードに欠けている情報を外挿、つまり発明しなければならない。正しく外挿するには判断が必要で、特に教師なしの言語モデルが大量に行う場合には、必然的に誤りが生じるプロセスだ。この問題をある程度緩和できると考える解決策を提案したことはあるが、詳細は述べない。
    最終的には、このプロジェクトはある程度の成功を収める可能性があると見ているが、慎重で抑制された期待値を持って進めるべきだ。同時に、公開された成果がまったく出ない可能性もあるため、現時点で過度に解釈しないようにと言いたい。特に政府は単一の存在ではないので、このプロジェクトをCに対する全面的な否定や、Rustに対する全面的な祝福と解釈してはならない。各機関はメモリ安全技術の導入方針とスケジュールを自ら決めるだろう。たとえばNISTはRustだけでなく、Ada SPARKや、複数の強化されたC/C++方言も推奨している。

    • GrammatechのCRAMの取り組みとはどのような関係があるのか?
      https://cpp-rust-assisted-migration.gitlab.io/blog/
    • Cコードの形式的意味を保存しようとせず、翻訳後もテストスイートさえ通ればよいと考えるなら、翻訳にははるかに多くの余地が生まれる。
      実際のRust化プロジェクトは、しばしばこのように進む。ファザーも追加のテストデータを作って分岐カバレッジを高める助けになり得る。
  • 個人的には「世界をすべてRustで書き直そう」という考え方は好きではない。とはいえ、あるプロジェクトを新しい言語やプラットフォームへ移植しようとするなら、機械的な翻訳は悪い方法だ。
    時間をかけてより良いアーキテクチャを計画し、より良いソフトウェアシステムを設計したうえで、部分ごとに置き換える方法を探すべきだ。空中に城を築いても、決して地面には届かない。このシステムにRustを使うことにしたのならそれはよいが、Rustらしく書くべきだ。CをRustへ逆移植しようとしてはいけない。
    はるかに良く成熟したプロセスは、Cを現代的なCへ更新し、CBMCのようなモデル検査器でメモリ、リソース、整数演算の安全性を検証することだと思う。段階的なRustでの再実装と同じ安全性を得ながら、コードベース、知識基盤、開発者を維持できる。

    • 可能性はない。CBMCは驚くべきものだが、「実際の」プログラムを形式検証したことがあるだろうか?
      手でアーキテクチャを設計したRust版に置き換えるのが明らかにより良い解決策だという点には同意するが、コストもより大きい。ここではRLBox式に「ほとんど労力をかけずにセキュリティを大きく改善する」製品を目指しているように見える。リソースがあるなら完全な手動での再実装をすべきでないという意味ではなく、やらないよりはましだという話だ。
    • 現代的なCも古典的なCと同じように、配列と文字列にセキュリティ脆弱性を抱えており、50年間何も変わっていない。
    • これはレガシーシステムから抜け出す際にあったらよさそうな、まさに雲をつかむようなDARPAの挑戦課題だ。しかし、ある言語の関数やメソッドをChatGPTに入れて別の言語に翻訳してくれと頼んでも、たいていうまくいかない。
      そもそも解こうとしている問題をChatGPTに聞けば、より頻繁に正解するとはいえ、それでもたいていうまくいかない。出力された基本的なものですら動くようにするには、依然として多くの手直しと思考が必要だ。
    • どこでも実行されているが誰も手を入れていない休眠コードなら、「再び触る前に粗末なRustへ翻訳する」というやり方には、ある程度の魅力がある。
      明らかに良いアイデアだという魅力ではない。翻訳で作られた「粗末なRust」は、バグという背景ノイズを抱えたCよりも、作業するにははるかに悪い可能性が高い。忠実な翻訳のおかげで、そのバグも「粗末なRust」にそのまま残るだろう。Cでは人々は問題への対処方法をある程度知っているが、「粗末なRust」はRustの人たちがそうしたものに慣れていないため、文字通り粗末なものになる。
      それでも、誰かが繰り返し整理して耐えられる状態にする技術を発展させる可能性はゼロではない。また、プロジェクトの非目標成果物として「x、y、zのため、耐えられるRustには翻訳できない」といったリンターのフィードバックが出てくる可能性もある。C開発者がそれを見直し、コードが良いRustへ翻訳可能になったなら、あえて翻訳する理由も減る。
      こうした結果が出るなら、ある人たちにとっては、実行可能なCで解法を記述し、「翻訳器/リンター」に壊れていないアプローチへ導かせるほうが簡単かもしれない。こうした前向きな結果はかなり可能性が低いと思うが、ときどきダークホースへの賭けをすることこそ、DARPAの職務内容に近いのではないかと思う。
    • 「世界をすべてRustで書き直そう」という考え方はどこにもない。動的言語やGoのようなガベージコレクション付きの静的型付け言語にそのまま置いておくほうが、はるかに良いソフトウェアは非常に多い。優れたエンジニアは、作業に合った道具を使うべきだという考えを理解している。
      重要なのは、実際に何度も問題になったことが証明されているメモリ安全性CVEを減らし始めようということだ。
      C/C++からRustへ自動かつ信頼性高く翻訳できていたなら、すでに実現していただろうという点には同意する。しかし、より良いアーキテクチャとシステムを計画して部分ごとに置き換えるプロセスのどこかで、人々は「もうCをずっと上手に書けているのだから、メモリ安全性バグはこれ以上作らないのではないか、ここで止めてもよいのではないか」という自信を持つことがあり、実際にそうするだろう。すると6か月後、また泣き笑いするようなバッファオーバーフローCVEが出てくる。
      Cを現代的なCへ更新してCBMCで検証するのも莫大な投資だ。その程度のことをするなら、むしろRustへ移行するほうがよい。段階的なRustでの再実装と同じ安全性を得るという話は可能かもしれないが、かなり不確実か、明確な結論からは程遠いように見える。
  • 多くの人がこれを、すべての C と C++ コードを Rust に翻訳せよという要求や命令として読んでいるが、目立つプロジェクト名とは違って、アブストラクトはそうは読めない。互いに関連はしているが、別個の2つの段落がある
    第一に、C と C++ は大規模では十分に安全ではない。慎重にプログラミングし、良いツールを使っても、根本的に安全ではない設計のためにあまりにも多くの脆弱性が生まれる。したがって、可能な限り多くのコードを「安全な」言語、特にメモリ安全性を保証する言語へ翻訳するか、新たに書くべきだ
    第二に、既存の C コードを Rust に翻訳するソフトウェアに資金を出し、公募するということだ
    世界を Rust で書き直そうという合意ではない。安全な言語へ移行しようという合意であり、Rust はその一例で、この移行において Rust をターゲットにするプログラムがあるという意味だ

    • そうした言語に unsafe 構文があるなら、それを使うルールはどうなるのか? ここで使う定義済みのルールセットがなければ、結局出発点に戻るだけだ
      Rust にはセーフモードがある。Rust が安全な言語というわけではない。面白いことをするには unsafe ブロックが必要になる。これでは多くは得られない
      一方で、プログラマにポインタを触らせさえしないガベージコレクション言語はたくさんある。なぜそうした言語は検討されないのか? 理由は性能だ。Rust プログラマたちが性能をそれほど「重視」するから、その言語では根本問題を決して解けない
      性能が欲しいのか、安全性が欲しいのか? 両方を手に入れることはできない
  • これが何らかの自動化方式で動き得るというのは本当に驚きだ。一般的な C プログラムを Rust に行単位で転写することはできない
    C プログラムにはポインタとエイリアスが至るところにあり、Rust はそうした概念を明示的に防ぐ。全体を unsafe で包まない限り、C プログラムを Rust で書き直すには、多くの典型的な構造をより高いレベルで考え直す必要がある

    • 行単位の翻訳は不可能で、だからこそより大きな意味論的推論を行うには AI を使う必要がある
      すべてを一度に翻訳する必要もない。Rust コンパイラの価値の一つは、LLM に戻して反復できる具体的な情報を大量に与えてくれる点だ
      私のスタートアップ grit.io では似た問題に取り組んできており、C -> Rust は近い将来に十分扱えるようになると見ている。確かに簡単ではないが、解決可能な問題だ
    • マルチスレッドプログラムを除けば、長期的なエイリアスは本当に C プログラム全般の至るところにあるのか? 多くのプログラムでは、その大半は単一関数のスコープ内、またはその中の関数呼び出しをまたいで起きると予想する。その場合は借用で解決できるのではないか?
      ならば、それを一つのサブ問題として扱い、スレッド間でデータがどう共有されるかを検出することを別の問題にできる。後者の場合、多くのプログラムには「スレッド T1 がキュー Q に入れ、スレッド T2 が取り出す」といった暗黙の所有権ルールがあるはずだ。これは「キューに入れると所有権が移転する」と翻訳できる
      こうしたルールを検出するのは簡単ではないだろうが、まったく手の届かないことにも見えず、研究プロジェクトとしては十分意味があり得る
    • 素朴な初心者の立場から聞くと、行単位で進めながら全体を unsafe で包み、同一のバイナリにコンパイルしたうえで、等価性を検証し続けながら unsafe を少しずつ外していくことはできないのか?
      そうすれば、少なくとも可能な限り多くの部分を Rust に持っていき、エンジニアが考え直すべき概念だけを別途扱えるように思う
    • 行単位の翻訳にはそれほど多くの「AI」も必要ない。おおまかな、ほとんどが unsafe の Rust 翻訳は作れる気がする
      AI が本当に有用で有効なプログラムを作るには、ライフタイムなどを把握しなければならないはずだ。本当にそれをやるなら印象的だろう
    • マクロを多用するコードベースでは、特にこれがどうなるのか気になる
  • 非常に厳格なコーディング慣行を守り、コードに独自アノテーションを大量に入れる必要があるサードパーティ製の静的検証ツールを統合すれば、C/C++ でも似た結果を得ることはできる
    あるいは、単に Rust を使えばいい

    • C/C++ コミュニティが Rust に反発するのを見るとかなり面白い。あの言語たちと付き合ってきた数十年の努力と経験が、明らかに推論回路を上書きしている
      本物の代替手段があるのに、あれほど大きく明白な設計上の欠陥がある言語を、正気で誰が擁護するというのか
    • 「独占状況」ではなく独自アノテーションと書くつもりだった。スマホのオートコンプリートのせいだ
  • これはうまくいきそうにない。C には Rust で大きな変更なしに再現できない抽象化がある
    C では、同じポインタを含む別々の2つのデータ構造が、そのポインタに書き込むことがよくある。これは Rust で自明に再現できず、かなり賢い介入が必要になる

    • コンパイルはでき、「Rust」でもあり「AI」でもある何かは作れる気がする。流行語の要件を二重に満たすので、研究プロジェクトを正当化するにも都合がいい
      だが、よりバグの少ない出力や、Rust の信頼性を生み出すプログラム構造を自動生成するプロセスは得られないだろう
  • これは自動でなければならないのか? だとすると、C を Rust に自動移植できるプログラムは、必然的に C コード自体を安全にする機能をすべて含んでいなければならないのではないか?

    • その文を合理的に読むなら、完全自動化を意味すると見るのは難しく、だとすれば質問への答えはノーだ
      ある C コードは単に「正しさを検証できない」のではなく、「メモリ安全性の面で実際に間違っている」。そうしたコードは人の介入なしには自動翻訳されないだろう。正しい等価コードがないのに、どうして可能だろうか。ツールには「このコードが何をしようとしているのか分からず、実際にしていることはコンパイラとの約束を破っているので、意図したことではないのも分かる。人間よ、助けてくれ」と言う逃げ道が必要だ
      理論上、その逃げ道が未定義動作が実際に発生するときだけ使われるようにすることは不可能だ。ライスの定理があるからだ。実務上も、過度に難解なコードを盲目的に翻訳すべきではないので、そうしようとする試み自体が望ましくない可能性が高い
      結局、ツールは作業の大半をこなしつつ、人が案内する対話型ツールのようなものになると想像している。そしてその人の案内の結果として、正確に等価なコードではなく、同じ目的を果たすコードが出てくることになるだろう
  • もし 1) Rust にはメモリバグがなく、2) C を Rust に自動翻訳できるなら、すべてのメモリバグを自動的に修正できることになる
    これはほぼ確実に事実ではない。この作業は一般的な場合には完全に不可能である可能性が非常に高い

    • C コードのあらゆる動作を保持したいとは明示していないので、この問題には些細な解法がある
      例えば、すべての動的メモリ割り当てを翻訳時点で決めた固定バッファに置き換え、そのバッファに収まらないすべての入力を拒否すればよい