ヒープ領域とは?
『山積み』という言葉の中の『山』という意味であり、プログラムが実行時にサイズを指定して確保できるメモリ上の領域の一つです。
※セットで説明されるメモリ領域に、スタック領域が挙げられます。
AppGoatではC/C++を前提に学ぶため、プログラマーがメモリ領域の確保/解放を意識する教えとなっていますが、
例えば.Net系の言語ならガベージコレクションがこの辺りをやってくれます。
自分が良く使う言語はどの様な仕様なのだろう?と調べるきっかけを与えてくれるのが、AppGoatで学ぶ一番の利点なのかもしれません。
C/C++でヒープ領域を扱うプログラム例
以下のCで書かれたコードを読んでみましょう。
char* str_dup(char* string) {
unsigned char size = 0;
char* buffer = NULL;
if (!string)
return NULL;
// ①変数sizeはunsigned char型で文字列の長さを受け取る
// +1 は Null 文字分
size = strnlen(string, 1000) + 1;
// ②変数sizeを使ってバッファを確保
buffer = (char*)malloc(size);
if (!buffer)
return NULL;
// ③strcpy関数で受け取った文字列stringをコピー
strcpy(buffer, string);
return buffer;
}
引数で渡された文字をコピーして返すC言語のソースです。
平成生まれ以降には少しなじみの浅い書き方なのかなと思います・・・
何が問題なのか?
10行目で文字列の長さをunsigned char型のsizeで受け取っています。ここが諸悪の根源であり、unsignd charは255までしか入りません。
※300文字の文字列を受け取ったら、sizeに45が格納されます。13行目で(1)で確保したサイズ分mallocでメモリ領域を確保します。
3.18行目で受け取った文字列stringとstrcpy関数を使って変数bufferにコピーする訳ですが、仮に300文字来た場合、45バイトしかメモリを確保していないため、255バイト分溢れてしまい、バッファーオーバフローを引き起こしてしまいます。
打つべき対策
IPAにC/C++に詳しい対策が載っていますので、興味がある方はご確認ください。
https://www.ipa.go.jp/security/awareness/vendor/programming/index.html
C/C++以外の言語の場合、コードで担保というより言語での担保になるので環境のパフォーマンスチューニングの世界になるのかなと思います。
Javaの場合
https://qiita.com/opengl-8080/items/64152ee9965441f7667b
Goの場合(意識する必要ないといった記事もちらほらありますが、githubのソースを。)
https://github.com/golang/go/blob/master/src/runtime/malloc.go
Pythonの場合(メモリ管理の崩壊を避けるため、Python オブジェクトを C ライブラリが公開している関数で操作しようとしてはなりません。という注意書き付き)
https://docs.python.org/ja/3/c-api/memory.html
C/C++に存在した脆弱性を知ると、今流行りの言語の方針が知れてとても面白いです。
それではまた次回。