Linuxカーネルソースで使用されている__userマクロのニュアンスを誰かが説明できることを望んでいました。
まず、マクロ:
# define __user __attribute__((noderef, address_space(1)))
さて、グーグルの後で、このマクロを使用すると、ポインタをユーザーアドレス空間に属するものとして指定でき、逆参照してはならないことを読みました。
私はいくつかの明らかな事実を見逃しているかもしれませんが、誰かがそのようなマクロの意味を説明してくれませんか?たとえば、このマクロが役立つ場所の良い例は何ですか?繰り返しますが、明らかなものがない場合は、ご容赦ください。
これをある文脈で説明するために、私はいくつかのUSBコード(linux/usbdevice_fs.h)を調べている間にマクロに遭遇しました。私は、カーネル内で使用されるこのマクロ(またはそのような他のマクロ)の一般的な理解のみを探しています。
見てくれてありがとう!
sparse のようなツールを使用して、信頼できないポインター(または現在の仮想アドレスマッピングでは無効なポインター)を不適切に使用している可能性があることをカーネル開発者に伝えることができます。
__userがユーザースペースポインターをマークし、開発者/システムにそれを信頼しないように指示すると思います。ユーザーが「無効な」ポインターを与えると、カーネルはそれを参照しようとし(カーネルはどこからでも参照できることに注意)、それ自体のスペースを破壊する可能性があります。
たとえば、 "read"(usbdevice_fs.h内)では、結果を書き込むための(__user)バッファーを提供する必要があります。したがって、copy_to_userを使用する必要がありますが、memcopy、strcpyなどは使用しないでください。
注:これは正式な定義/説明ではありませんが、私が知っている唯一の部分です。
__user
マクロは、compiler.hヘッダーファイルで__force
/__kernel
などの他のいくつかのマクロで定義されています。実際には、GCC/ICCなどの従来のコンパイラーにはまったく役に立ちません。ただし、sparseなどのカーネル静的分析ツール(詳細はSparse-Linux Kernel Newbies)に役立ちます。 __user
/__kernel
/__force
などのマクロについて言及すると、スパースにとって特別な意味が保持されます。 Linuxカーネルメーリングリストでは、Linus Torvaldsがその使用法を次のように説明しています。
これは覚えておくことが重要です。gccの場合、スパースアノテーションは無意味です。 programmerに、「わかりました、取得したポインタは通常のポインタではなかった」とかなり読みやすい方法で伝えるだけでも、依然として役立ちますが、結局、スパースを使用しない限り、実際にはdo何でも。
しかしながら。 do parseを使用する場合、それは完全に別の問題です。 「スパース」の場合、「__ iomem」には多くの意味があります。
# define __iomem __attribute__((noderef, address_space(2)))
つまり、「iomem」は2つの別個のことを意味します。つまり、スパースが文句を言うべきです。
ポインターが直接間接参照される場合( "noderef"ポインター)、通常のアドレス空間(0)ではなく "アドレス空間2"にある場合。
これは、通常のポインタを必要とする関数にそのようなポインタが渡されると、-sparseが文句を言うことを意味します(これはnotが通常のポインタなので、明らかに「strcmp()」などのようなことはしないでください。また、スパースは、別のアドレス空間の別のポインタにキャストしようとすると文句を言います。