説明
コピーするデータがヒープバッファーに収まることを確認せず、固定または計算した長さでコピーすると、確保した領域の外に書き込むおそれがあります。
想定される影響
- ヒープのメタデータ破損、クラッシュ、任意のコード実行につながる可能性があります。
対処方法
検証済みの同じ値から確保するサイズとコピー長を計算し、コピー前に書き込み先の容量を確認してください。
例
変更前
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は使いません。