LinuxカーネルのRust





では  以前の記事 、GoogleはAndroidがサポートされるようになりましたことを発表しました錆のプログラミング言語 OS自体の開発に使用します。この点で、この出版物の著者は、Linuxカーネルの開発においてRust言語がどれだけ需要があるかを評価することも決定しました。この投稿では、いくつかの簡単な例を使用して、この作業の技術的な側面について説明します。



Cは、このような重要なコンポーネントに必要な制御の程度と予測可能なパフォーマンスを提供するため、半世紀近くの間、Cはカーネル開発の主要言語でした。 Linuxカーネルのメモリセキュリティバグの密度は、コードが非常に高品質であり、コードレビューが厳格な基準に準拠しており、セーフガードが慎重に実装されているため、通常は非常に低くなっています。ただし、  メモリの安全性に関連するバグは依然として定期的に発生します。 Androidでは、カーネルの脆弱性は、カーネルが特権モードで実行されているためにセキュリティモデルがバイパスされることがあるため、一般に重大な欠陥と見なされます。



Rustは、カーネルの実際の実装のための言語としてCと協力するのに十分成熟したと思われます。Rustは、コアコアと適切に統合し、優れたパフォーマンスを維持しながら、特権コードの潜在的なバグとセキュリティの脆弱性を減らすのに役立ちます。



さびのサポート



 バインダードライバーのプライマリプロトタイプは、既存のCバージョンとそれに対応するRustのセキュリティとパフォーマンスの特性を適切に比較するために開発さ  れました。 Linuxカーネルには3000万行を超えるコードがあるため、Rustで完全に書き直すという目標を設定するのではなく、Rustで必要なコードを追加する機能を提供します。このインクリメンタルアプローチは、カーネルの高性能実装を活用すると同時に、カーネル開発者にメモリの安全性を向上させ、実行時のパフォーマンスを維持するための新しいツールを提供するのに役立つと考えています。 Rust forLinux



組織に参加しました  コミュニティは、LinuxカーネルビルドシステムにRustサポートを追加するために多くのことを行っており、これからも多くのことを続けています。また、2つの言語で記述されたコードフラグメントが相互に作用できるようにシステムを設計する必要があります:RustコードがCで記述されたコア機能を使用できるようにするオーバーヘッドのない安全な抽象化と実装機能に特に関心がありますCで記述されたカーネルの一部からスムーズに呼び出すことができる慣用的なRustの機能。 



Rustはコアの新しい言語であるため、ドキュメントと一貫性のベストプラクティスに従うよう開発者に義務付けることもできます。たとえば、安全でないコードの使用に関して、マシンで検証可能な特定の要件があります。安全でない関数ごとに、開発者は呼び出し元が満たさなければならない要件を文書化する必要があります。これにより、使用が安全であることを確認できます。さらに、安全でない関数が呼び出されるたびに、使用が安全であることを保証するために、呼び出し元が満たさなければならない要件を文書化するのは開発者の責任です。さらに、安全でない関数の呼び出し(または、たとえば、安全でない構造の使用)ごとに生のポインタを逆参照する場合)、開発者は、そうすることが非常に安全である理由を文書化する必要があります。



Rustは、セキュリティだけでなく、開発者にとってどれほど便利で使いやすいかで有名です。次に、安全で正しいドライバーを作成するときにRustがカーネル開発者にとってどのように役立つかを示すいくつかの例を見てみましょう。



ドライバーの例



セマフォシンボリックデバイスの実装を検討してください。各デバイスには実際の値があります。n バイトを書き込む 場合、デバイス値はnだけ増加し ます。値が0になるまで、それぞれの読み取りと、この値は1だけ減少させ、そのようなAのデクリメント操作が0未満に行かなくても、それに実行できるようになるまで、このデバイスがブロックされている場合には



ましょうと言う  semaphore



 、これは私たちのデバイスを表すファイルです。次のようにシェルから操作できます。 



> cat semaphore

      
      





場合  semaphore



 だけ初期化されたデバイスである現在のデバイス値が0であるので、上記のコマンドは、我々は別のシェルから次のコマンドを実行する場合、それはこのように可能に、1の値をインクリメントするようにそれは、ロック解除されロックされています完了するための元の操作の読み出し:



> echo -n a > semaphore

      
      





次のように、より多くのデータを書き込む場合は、カウンターを1以上増やすこともできます。



> echo -n abc > semaphore

      
      





カウンターを3増やすので、次の3つの読み取り値はブロックされません。 



Rustのいくつかの側面を示すために、次の機能をドライバーに追加しましょう。ライフサイクル全体で到達した最大値を記憶し、デバイスで実行された各ファイルの読み取り回数も記憶します。



次に、このオプションをCでの実装と比較して、このようなドライバーがRustどのように実装されるかを示しましょう  ..。ただし、Googleでのこのトピックの開発はまだ始まったばかりであり、将来的にはすべてが変わる可能性があることに注意してください。Rustが開発者にとってあらゆる面でどのように役立つかを強調したいと思います。たとえば、コンパイル時に、コードの柔軟性を維持し、最小限のオーバーヘッドで実行しながら、バグのクラス全体がコードに忍び寄る可能性を排除または大幅に削減できます。



キャラクターデバイス



開発者は、Rustに新しいキャラクターデバイスのドライバーを実装するために、次のことを行う必要があります。



  1. 特性の実装 FileOperations



    :それに関連するすべての機能はオプションであるため、開発者は特定のシナリオに関連する機能のみを実装する必要があります。これらは、C構造体のフィールドに対応します struct file_operations



  2. トレイトの実装は  、構造体の FileOpener



     Cフィールドに相当するタイプセーフ です。open



    struct file_operations



  3. カーネルに新しいデバイスタイプを登録します。これにより、新しいタイプのファイルに対する操作に応答して呼び出す必要のある関数がカーネルに通知されます。


以下は、RustとCの最初の例の最初の2つのステップの比較です。Rustの







キャラクターデバイスには、いくつかのセキュリティ上の利点があります。



  • ファイルごとのライフサイクル状態管理: FileOpener::open



     それ以降の存続期間が呼び出し元によって所有されているオブジェクトを返します。トレイトを実装する任意のオブジェクトを返すことができ、次の実装  PointerWrapper



    を提供します 
    ボックス<T>
     そして 
    アーク<T>
    , , Rust, , .



     FileOperations



      self



     ( ),  release



    , ( ).  release



      , - , . «» ( , ).



    , Rust , C. C , Rust, , Rust, , , . , C, Rust , Rust. , open , , , , ioctl



    /read



    /write



      ( ) ,  filp->private_data



    , ..



  • : , open



      release



       self



    , , Rust , .



    ( ),   : Mutex



      
    SpinLock



     ( 
    atomics) .



    , ( ), ( ). 





    : , , Rust . , , ,  FileOperation::open



    .  Arc, .



    ,  FileOperation




      ( , ,  open



    ,  FileOperations



    ) – .



    , , . , C miscdevice



    ,  filp->private_data



    ;  cdev



    , inode->i_cdev



    . , ,  container_of



    , . Rust .









    : , Rust , . . C , , (void



     *) : , , . Rust .





    : ,  FileOperations



    , . , impl FileOperations for Device



    ,  Device



     – , ( FileState



    ). , , , . (  neovim



      LSP- rust-analyzer



     .)



    Rust, , C, struct file_operations



    . (  declare_file_operations



    ): , , ,  const



    , , .



    Ioctl 



     ioctl, ioctl



    , FileOperations



    , . 







    Ioctl , , , , , (, , , , ) . Rust  (  cmd.dispatch



    ), .



       . , , ioctl, Rust : cmd.raw



      ioctl ( , ).



    , , , - , :





    C, ( , ) ; Rust  unsafe



    , . Rust:





     



    . ; , C Rust , , , , : 







    , C, ,    «» ,  unix  ,     ,   .



    Rust:



    •  Semaphore::inner



        , ,  lock



      . , . C, , count



        max_seen



        semaphore_state



        , . there is no enforcement that the lock is held while they're accessed.
    • (RAII): , (inner



        ) . , : , , , , ; : , , , drop



      .
    • ,  Lock



      , , , Mutex



        SpinLock



      , , C, . , , , .
    • Rust , . , , . C  semaphore_consume



        Linux: , ,  mutex_unlock



         prepare_to_wait



      , . 
    • : , , , , , . , ioctl , , . Rust ,   . , C, atomic64_t



      , , . 






    ,  open



    read



     write



    :















    Rust:



    •  ?



       operator: open



        read



        Rust ; , , , . C , - . 
    • : Rust , , - . C . open



      , , C kref_get



       ( ); Rust  clone



       ( ), .
    • RAII: Rust , , inner



        , , .
    • : Rust , . write



      , , . C , , . 







    .



    10% !






All Articles