[하루한줄] CVE-2024-5171: libaom의 integer overflow 취약점
URL
https://issues.chromium.org/issues/332382766
Target
- libaom < v3.9.0
- libvpx < v1.14.1
Explain
오픈소스 비디오 코덱 라이브러인 libaom에서 발견된 integer overflow 취약점의 세부 정보가 공개되었습니다.
취약점은 aom/src/aom_image.c
의 이미지 버퍼를 새로 할당하는 img_alloc_helper()
함수에 존재합니다.
// static aom_image_t *img_alloc_helper(
// aom_image_t *img, aom_img_fmt_t fmt, unsigned int d_w, unsigned int d_h,
// unsigned int buf_align, unsigned int stride_align, unsigned int size_align,
// unsigned int border, unsigned char *img_data,
// aom_alloc_img_data_cb_fn_t alloc_cb, void *cb_priv) {
32 unsigned int h, w, s, xcs, ycs, bps, bit_depth;
// ...
107 /* Calculate storage sizes given the chroma subsampling */
108 w = align_image_dimension(d_w, xcs, size_align);
109 h = align_image_dimension(d_h, ycs, size_align);
110
111 s = (fmt & AOM_IMG_FMT_PLANAR) ? w : bps * w / bit_depth; <==== s and w are 32-bit integer variable
112 s = (s + 2 * border + stride_align - 1) & ~(stride_align - 1);
113 stride_in_bytes = s * bit_depth / 8; <==== Integer overflow occurred, causing stride_in_bytes to become a smaller value.
114
line 32
에서는 이미지 연산을 위해 사용하는 변수들을 32bit 크기의 unsigned int
타입으로 선언합니다. 이후 line 111
및 line 112
에서 이미지의 stride 크기인 stride_in_bytes
를 계산하는데, 이 과정에서 계산 결과가 unsigned int
범위를 넘는 경우 integer overflow가 트리거되어 stride_in_bytes
가 예상보다 작은 값이 됩니다.
stride : width와 유사하게 이미지의 한 줄(row)크기를 의미하지만, width와 다르게 padding 등을 포함한 크기입니다. stride는 반드시 width보다 크거나 같아야 합니다.
115 /* Allocate the new image */
116 if (!img) {
117 img = (aom_image_t *)calloc(1, sizeof(aom_image_t));
118
119 if (!img) goto fail;
120
121 img->self_allocd = 1;
122 }
123
124 img->img_data = img_data;
125
126 if (!img_data) {
127 const uint64_t alloc_size =
128 (fmt & AOM_IMG_FMT_PLANAR)
129 ? (uint64_t)(h + 2 * border) * stride_in_bytes * bps / bit_depth
130 : (uint64_t)(h + 2 * border) * stride_in_bytes;
131
132 if (alloc_size != (size_t)alloc_size) goto fail;
133
134 if (alloc_cb) {
135 const size_t padded_alloc_size = (size_t)alloc_size + buf_align - 1;
136 img->img_data = (uint8_t *)alloc_cb(cb_priv, padded_alloc_size);
137 if (img->img_data) {
138 img->img_data = (uint8_t *)aom_align_addr(img->img_data, buf_align);
139 }
140 img->img_data_owner = 0;
141 } else {
142 img->img_data = (uint8_t *)aom_memalign(buf_align, (size_t)alloc_size); <==== Object allocation
143 img->img_data_owner = 1;
144 }
145 img->sz = (size_t)alloc_size;
146 }
이후 line 127 ~ 130
에서 예상보다 작게 계산된 stride_in_bytes
를 이용해 alloc_size
를 계산한 뒤 line 142
에서 alloc_size
만큼 이미지를 할당합니다.
할당한 새 이미지 오브젝트 img
의 img_date
및 sz
필드에는 각각 할당된 메모리 주소, alloc_size
가 저장됩니다.
147
148 if (!img->img_data) goto fail;
149
150 img->fmt = fmt;
151 img->bit_depth = bit_depth;
152 // aligned width and aligned height
153 img->w = w;
154 img->h = h;
155 img->x_chroma_shift = xcs;
156 img->y_chroma_shift = ycs;
157 img->bps = bps;
img
오브젝트의 w
필드에는 원본 w
값이 저장되는데, 이후 해당 이미지를 처리할 때 img→w
를 이용해 계산된 이미지 크기가 integer overflow로 예상보다 작은 stride_in_bytes
로 계산된 alloc_size
보다 클 수 있어 alloc_size
만큼 할당된 heap을 넘어 heap overflow로 이어질 수 있습니다.
취약점의 패치는 unsigned int
타입으로 선언된 변수들을 uint64_t
타입으로 변경하는 것으로 이루어졌습니다.
diff --git a/aom/src/aom_image.c b/aom/src/aom_image.c
index 3b1c33d05..60459bf71 100644
--- a/aom/src/aom_image.c
+++ b/aom/src/aom_image.c
@@ -36,7 +36,7 @@ static aom_image_t *img_alloc_helper(
/* NOTE: In this function, bit_depth is either 8 or 16 (if
* AOM_IMG_FMT_HIGHBITDEPTH is set), never 10 or 12.
*/
- unsigned int h, w, s, xcs, ycs, bps, bit_depth;
+ uint64_t h, w, s, xcs, ycs, bps, bit_depth;
unsigned int stride_in_bytes;
if (img != NULL) memset(img, 0, sizeof(aom_image_t));
libaom과 유사한 구현의 libvpx의 vpx_img_alloc()
함수에도 동일한 integer overflow 취약점이 발견되어 CVE-2024-5197이 할당되었습니다.
본 글은 CC BY-SA 4.0 라이선스로 배포됩니다. 공유 또는 변경 시 반드시 출처를 남겨주시기 바랍니다.