ヒープバッファーへのコピーによるオーバーフロー

動的に確保したヒープバッファーへのコピーによるオーバーフロー

説明

コピーするデータがヒープバッファーに収まることを確認せず、固定または計算した長さでコピーすると、確保した領域の外に書き込むおそれがあります。

想定される影響

  • ヒープのメタデータ破損、クラッシュ、任意のコード実行につながる可能性があります。

対処方法

検証済みの同じ値から確保するサイズとコピー長を計算し、コピー前に書き込み先の容量を確認してください。

例

変更前

c
/* width、height、data_lenはsize_tで、dataはdata_lenバイトを指します。 */
struct Image img = load_image();
int size = img.width + img.height;
char *buf = malloc(size);
memcpy(buf, img.data, sizeof(img.data));

変更後

c
struct Image img = load_image();
const size_t bytes_per_element = 4;
size_t elements;
if (img.width > SIZE_MAX - img.height) { return; }
elements = img.width + img.height;

if (elements > SIZE_MAX / bytes_per_element) { return; }
size_t capacity = elements * bytes_per_element;
if (img.data_len > capacity) { return; }

unsigned char *buf = malloc(capacity);
if (buf == NULL) { return; }
memcpy(buf, img.data, img.data_len);

解説:

  • 変更前: 計算した確保サイズ size と実際のコピー長の関係を確認していません。img.data がポインターなら、sizeof(img.data) はデータ全体の長さではなくポインターのサイズです。
  • 変更後: width、height、data_len は size_t であることを前提に、加算とバイト数の乗算をそれぞれ SIZE_MAX に対して検証します。実際のソース長 data_len が容量以下であることと、メモリの確保に成功したことを確認してから、検証済みのバイト数だけコピーします。ポインターである可能性がある img.data に sizeof は使いません。

参考資料