この回答にもリンクされているこのドキュメントは、部門でより明確にする必要があります。興味深い抜粋(私が太字のテキストを追加したもの)は次のようになります。
ユーザースペースでは、ioctlシステムコールには次のプロトタイプがあります。
int ioctl(int fd, unsigned long cmd, ...);
プロトタイプは、通常、関数に可変数の引数があることを示すドットがあるため、Unixシステムコールのリストで際立っています。ただし、実際のシステムでは、システムコールに可変数の引数を含めることはできません。ユーザープログラムはハードウェアの「ゲート」を介してのみシステムコールにアクセスできるため、システムコールには明確に定義されたプロトタイプが必要です。したがって、プロトタイプのドットは、可変数の引数ではなく、従来はとして識別されていた単一のオプションの引数char *argp
を表します。ドットは、コンパイル中の型チェックを防ぐために単にあります。3番目の引数の実際の性質は、発行されている特定の制御コマンドによって異なります。(2番目の引数)。一部のコマンドは引数をとらず、一部は整数値を取り、一部は他のデータへのポインタを取ります。ポインターの使用は、任意のデータをioctl呼び出しに渡す方法です。その後、デバイスはユーザースペースと任意の量のデータを交換できます。
ioctl呼び出しの構造化されていない性質により、カーネル開発者の間で支持されなくなりました。各ioctlコマンドは、基本的に、個別の、通常は文書化されていないシステムコールであり、これらの呼び出しを監査する方法はありません。あらゆる種類の包括的な方法で。また、非構造化ioctl引数をすべてのシステムで同じように機能させることも困難です。たとえば、32ビットモードで実行されているユーザースペースプロセスを備えた64ビットシステムについて考えてみます。その結果、他のほぼすべての手段でその他の制御操作を実装するという強いプレッシャーがあります。考えられる代替案には、データストリームへのコマンドの埋め込み(この章の後半でこのアプローチについて説明します)、またはsysfsまたはドライバー固有のファイルシステムのいずれかの仮想ファイルシステムの使用が含まれます。(第14章でsysfsを見ていきます。)しかし、実際のデバイス操作にはioctlが最も簡単で最も簡単な選択であることが多いという事実は変わりません。
これは、デバイスドライバーの規則/内部に関する洞察に満ちた知識がなければ、ioctl引数を外部オブザーバーとして解釈する方法を理解する方法がないことを意味します。ioctl引数は、ユーザースペースの観点からは型指定されておらず、カーネルスペースでは、スペースを予約するためだけに扱われるため、どういうわけか大まかに型付けされています。unsigned long
これは「純粋な」数値またはスペースに収まる任意のビットシーケンスでありunsigned long integer
、(非常に短い)文字列、(小さな)char配列、(小さな)構造体として使用できますが、エンディアンとアーキテクチャ固有に注意してくださいサイズ-デバイスのオンボードチップのオペコードを表すことも、タイプpuningによってフロートとして処理することもできます。
また、これは、一貫性のないデータ(間違ったデータだけでなく、間違ったタイプの間違ったデータ!)をドライバーに渡すことによって、物事を台無しにするのが非常に簡単であることを意味します。読み取りioctlで間違ったサイズの構造体へのポインターを渡すことによって)。
さらに数行:
[...]cmd
引数は変更されずにユーザーから渡され、オプションの引数は、ユーザーが整数またはポインターとして指定したかどうかに関係なく、arg
の形式で渡されます。unsigned long
呼び出し側プログラムが3番目の引数を渡さない場合、arg
ドライバー操作によって受け取られる値は未定義です。追加の引数では型チェックが無効になっているため、無効な引数がioctlに渡された場合、コンパイラーは警告を表示できず、関連するバグを見つけるのは困難です。
とにかく、ヘッダーファイルとソースファイルを調べずに、デバイスドライバーのioctl呼び出しの「ブラインド」監査を試したい場合は、copy_from_user()を使用して、最初にargをポインターとして処理してみてください。即時値(またはエラーが発生した場合)の場合、その値をログに記録して外観を確認し、解釈を試みることができます(ただし、ドライバーコードを調べる代わりにioctlを逆にするのはなぜですか?)。成功すると、知識がなくても、さまざまなサイズのメモリを読み取ってログに記録し、デコードを試みることができます(ここでも、ソースが利用可能である限り、無意味です)。
より興味深い操作は、確かにioctlコード(cmd)をデコードすることです。これは、正しい方向を指し、その数値が関連付けられているドライバーを見つけることができるためです。ioctl定義の規則が次の場合、1つだけである必要があります。適用すると、とにかく異なるドライバーが同じ魔法の文字を使用できるため#define
、「r」や「D」などを含むすべてのカーネルソースファイルをgrepする正規表現は、ioctl定義を検査するために多数のファイルを選択できます。 、関数番号と照合するよりも、いくつかまたはすべての間違ったものを分類する必要があり、正しい引数サイズを探すと検索が完了します。
よろしく。