著作一覧 |
厚木方面で見たことある。
TechEDの安全コードのセッションで、テオ(シーオか?)はMSが雇ったことがあるハッカーの中でも特別な存在で、まさにCをしゃべるために生まれてきたみたいだった、といような余談の中で、そのテオのありがたいお言葉として「幾らコードを眺めてもわからん、それが算術演算がらみのバグだ」ってのを紹介していた。Cをしゃべる男がそういうくらいだから我々凡人はコードを眺める以前の段階から攻めなきゃならない。
で、その理由はCの型上げ規則が複雑だということととかいろいろ。
// len.c (注:このコードがセッションに出てきたわけではない。思い出しながら再構成している) #include <stdio.h> #include <stdlib.h> #include <limits.h> #if defined(BUG) int SIZE = 1024; #else size_t SIZE = 1024; #endif void copy(char* p, int off, int len) { char buff[SIZE]; int end = strlen(p); if (off + len > end) { printf("argment overflow: bad off=%d, len=%d, real=%d\n", off, len, end); } else if (len + 1 > SIZE) { printf("buffer overflow: bad off=%d, len=%d, real=%d\n", off, len, end); } else { strncpy(buff, p + off, len); buff[len] = 0; puts(buff); } } int main(int argc, char* argv[]) { copy("abc", 0, SIZE_MAX - 1); }に対して
$gcc len.c -o len;./len buffer overflow: bad off=0, len=-2, real=3 $gcc -DBUG len.c -o len;./len セグメント例外 (core dumped)
コードの見た目は引数の長さを越えたり、バッファ長を越えたりしないように検証しているように見える。しかし、SIZEという定数の型の違いで正しく弾くこともできれば、死ぬこともできる。
結論は、負になるはずが無い長さを符号付きの型で宣言するな、というのが教訓(っていうか、そのためのsize_t)。
#追記:もう、strncpyとかsnprintfとかは常識なので、今の攻撃側のトレンドは上の例のような算術オーバーフローを利用したバッファオーバーフローらしい。ジェズイットを見習え |