手动编译 libwebp——我们针对 CVE 2023-4863 的缓解方案
CVE-2023-4863 是一个缓冲区溢出漏洞,影响了 libwebp
库,该库是一个用于处理 WebP 图片的开源库,由 Google 开发,好巧不巧,我们的开源组件 WebP Server Go 和 SaaS 服务 WebP Cloud Services 都使用了这个库。
相关的修复 PR: https://github.com/webmproject/libwebp/commit/902bc9190331343b2017211debcec8d2ab87e17a, PR 中尝试解决的问题:
Huffman编码表构建问题:在 VP8L 图像编码/解码库中,存在一个名为
BuildHuffmanTable
的函数,用于构建 Huffman 编码表。之前的代码中存在一个潜在的问题,即在构建 Huffman 编码表时,有时可能会导致访问超出分配内存范围,这可能导致内存越界写入问题。修复这个问题的方式是对内存分配和访问进行了更严格的控制,以确保不会超出分配的内存范围。Huffman编码表的内存分配和释放:该补丁还引入了一种新的方式来管理 Huffman 编码表的内存分配和释放。通过引入
HuffmanTables
结构以及HuffmanTablesSegment
结构,它提供了更灵活的内存管理,允许在需要时动态分配更多的内存段,以避免内存不足问题,并确保分配的内存块是连续的。
以上内容由 ChatGPT 生成。
鉴于我们暂时没有在公开的地方找到 PoC ,且我们还没研究透怎么构造一个 PoC,我们的工作重心优先放在了修复上,这个漏洞主要的影响在于 Decode 的部分,所以对于浏览器端而言可能可以通过一个恶意的 WebP 图片造成溢出,对于 WebP Server Go 和 WebP Cloud Services 而言,攻击面应该在于源站上构造一个恶意的 WebP 图片,然后在我们服务尝试 Decode 的时候触发溢出。
修复/缓解方式有两种:
- 禁用 WebP 作为源站图片,但是我们看了一下在 WebP Cloud Services 上已经有不少用户在使用 WebP 作为源站图片了,所以这个方案不可行
- 更新
libwebp
库
目前各个发行版的打包速度还比较慢,在本文编写的时候可以看到以下发行版的修复情况(已经修复的版本是 1.3.2
,所以低于这个版本的 libwebp
都可能不包含这个 Fix,但是也有例外情况,就是发行版在老版本上打了 Patch):
Ubuntu 22.04 ✅
root@6134fe90ec67:/# apt-cache policy libwebp-dev
libwebp-dev:
Installed: (none)
Candidate: 1.2.2-2ubuntu0.22.04.2
Version table:
1.2.2-2ubuntu0.22.04.2 500
500 http://ports.ubuntu.com/ubuntu-ports jammy-updates/main arm64 Packages
500 http://ports.ubuntu.com/ubuntu-ports jammy-security/main arm64 Packages
1.2.2-2 500
500 http://ports.ubuntu.com/ubuntu-ports jammy/main arm64 Packages
根据 https://changelogs.ubuntu.com/changelogs/pool/main/libw/libwebp/libwebp_1.2.2-2ubuntu0.22.04.2/changelog ,这个 Patch 版本包含了 Fix
libwebp (1.2.2-2ubuntu0.22.04.2) jammy-security; urgency=medium
- SECURITY UPDATE: Heap buffer overflow in BuildHuffmanTable
- debian/patches/CVE-2023-4863.patch: fix OOB write in BuildHuffmanTable in src/dec/vp8l_dec.c, src/dec/vp8li_dec.h, src/utils/huffman_utils.c, src/utils/huffman_utils.h.
- CVE-2023-4863
– Marc Deslauriers marc.deslauriers@ubuntu.com Wed, 13 Sep 2023 13:57:14 -0400
Debian 12 ✅
root@581497e00c7b:/# apt-cache policy libwebp-dev
libwebp-dev:
Installed: (none)
Candidate: 1.2.4-0.2+deb12u1
Version table:
1.2.4-0.2+deb12u1 500
500 http://deb.debian.org/debian-security bookworm-security/main arm64 Packages
1.2.4-0.2 500
500 http://deb.debian.org/debian bookworm/main arm64 Packages
根据 https://metadata.ftp-master.debian.org/changelogs//main/libw/libwebp/libwebp_1.2.4-0.2+deb12u1_changelog ,这个 Patch 版本包含了 Fix
libwebp (1.2.2-2ubuntu0.22.04.2) jammy-security; urgency=medium
- SECURITY UPDATE: Heap buffer overflow in BuildHuffmanTable
- debian/patches/CVE-2023-4863.patch: fix OOB write in BuildHuffmanTable in src/dec/vp8l_dec.c, src/dec/vp8li_dec.h, src/utils/huffman_utils.c, src/utils/huffman_utils.h.
- CVE-2023-4863
– Marc Deslauriers marc.deslauriers@ubuntu.com Wed, 13 Sep 2023 13:57:14 -0400
libwebp (1.2.4-0.2+deb12u1) bookworm-security; urgency=medium
- CVE-2023-4863
– Moritz Mühlenhoff jmm@debian.org Tue, 12 Sep 2023 21:35:44 +0200
Alpine 3.18 ✅
/ # cat /etc/issue
Welcome to Alpine Linux 3.18
Kernel \r on an \m (\l)
/ # apk info libwebp-dev
libwebp-dev-1.3.2-r0 description:
Libraries for working with WebP images (development files)
libwebp-dev-1.3.2-r0 webpage:
https://developers.google.com/speed/webp
libwebp-dev-1.3.2-r0 installed size:
160 KiB
Fedora 38 ❌
[root@9dd00c8c57b8 ~]# yum info libwebp-devel
Last metadata expiration check: 0:00:37 ago on Sat Sep 16 12:25:45 2023.
Available Packages
Name : libwebp-devel
Version : 1.3.1
Release : 3.fc38
Architecture : aarch64
Size : 38 k
Source : libwebp-1.3.1-3.fc38.src.rpm
Arch Linux ✅
[root@bbacbc426a03 ~]# pacman -Ss libwebp
extra/libwebp 1.3.2-1
WebP library and conversion tools
CentOS Stream 9 ❌
[root@69de863356a0 /]# yum info libwebp-devel.x86_64
Last metadata expiration check: 0:01:42 ago on Sat Sep 16 12:35:25 2023.
Available Packages
Name : libwebp-devel
Version : 1.2.0
Release : 7.el9
Architecture : x86_64
OpenSUSE Tumbleweed ❌
9f749cc56bcb:/ # zypper info libwebp-devel
Loading repository data...
Reading installed packages...
Information for package libwebp-devel:
--------------------------------------
Repository : openSUSE-Tumbleweed-Oss
Name : libwebp-devel
Version : 1.3.1-2.1
Arch : x86_64
Vendor : openSUSE
我们的修复
鉴于几个发行版基本没有修复,而我们又受到此漏洞的影响,且由于我们是 Multi-stage 的容器化构建,所以前置的 RUN apt update && apt install --no-install-recommends libvips-dev -y && mkdir /build
及以上的部分可能一直会被缓存,导致我们一直没法得到带 Patch 的版本,正好我们也打算升级一下 libwebp 的版本,因此我们需要手动编译新版本的 libwebp
。
由于我们的服务是跑在容器中的,并且在 Dockerfile
中我们使用了 multi-stage build,那么我们要做的事情只是添加一个 stage,编译成我们所需的 so
文件,然后把最后的这个 so
文件复制到运行的 stage 里
检查so文件
在安装 libwebp
的时候,会自动带上这些依赖:libwebp-dev libwebp7 libwebpdemux2 libwebpmux3
使用 dpkg -L
可以看到 so
文件,最终我们要全部替换掉
root@ee54b6e5dbfa:/# dpkg -L libwebp-dev libwebp7 libwebpdemux2 libwebpmux3 | grep "so"
/usr/lib/aarch64-linux-gnu/libwebp.so
/usr/lib/aarch64-linux-gnu/libwebpdemux.so
/usr/lib/aarch64-linux-gnu/libwebpmux.so
/usr/lib/aarch64-linux-gnu/libwebp.so.7.1.5
/usr/lib/aarch64-linux-gnu/libwebp.so.7
/usr/lib/aarch64-linux-gnu/libwebpdemux.so.2.0.11
/usr/lib/aarch64-linux-gnu/libwebpdemux.so.2
/usr/lib/aarch64-linux-gnu/libwebpmux.so.3.0.10
/usr/lib/aarch64-linux-gnu/libwebpmux.so.3
安装编译前依赖
注意
libgif-dev
,少了这个就没法生成 GIF 动图了
apt install -y wget gcc make autoconf automake libtool libgif-dev \
libjpeg-dev libjpeg62-turbo libjpeg62-turbo-dev libpng-dev libpng-tools libpng16-16 libtiff-dev libtiff6 libtiffxx6
下载源代码并配置编译
mkdir libwebp && mkdir -p /build/usr && mkdir /build/usr/lib/ && cd libwebp && \
wget https://chromium.googlesource.com/webm/libwebp/+archive/refs/heads/1.3.2.tar.gz && \
tar xf 1.3.2.tar.gz && rm -f 1.3.2.tar.gz && \
./autogen.sh && \
./configure --prefix=/build/usr --libdir=/build/usr/lib --enable-everything && \
在 ./configure
时,由于我们并不真正需要安装到这个系统中,所以我们创建一个临时的 /build
目录,通过 --prefix
和 --libdir
来输出 so
文件到这个目录之中。
配置完成之后会输出如下信息,共享库、encoder、decoder、mux 和 demux 都有,并且 JPEG PNG TIFF和 GIF 的支持都在。这样编译出来的 so
就是我们要的运行时链接库文件。
WebP Configuration Summary
--------------------------
Shared libraries: yes
Static libraries: yes
Threading support: yes
libwebp: yes
libwebpdecoder: yes
libwebpdemux: yes
libwebpmux: yes
libwebpextras: yes
Tools:
cwebp : yes
Input format support
====================
JPEG : yes
PNG : yes
TIFF : yes
WIC : no
dwebp : yes
Output format support
=====================
PNG : yes
WIC : no
GIF support : yes
anim_diff : yes
gif2webp : yes
img2webp : yes
webpmux : yes
vwebp : no
webpinfo : yes
SDL support : no
vwebp_sdl : no
编译
make && make install
检查一下编译结果
root@ee54b6e5dbfa:~/libwebp# tree /build
/build
`-- usr
|-- bin
| |-- cwebp
| |-- dwebp
| |-- gif2webp
| |-- img2webp
| |-- webpinfo
| `-- webpmux
|-- include
| `-- webp
| |-- decode.h
| |-- demux.h
| |-- encode.h
| |-- mux.h
| |-- mux_types.h
| |-- sharpyuv
| | |-- sharpyuv.h
| | `-- sharpyuv_csp.h
| `-- types.h
|-- lib
| |-- libsharpyuv.a
| |-- libsharpyuv.la
| |-- libsharpyuv.so -> libsharpyuv.so.0.0.1
| |-- libsharpyuv.so.0 -> libsharpyuv.so.0.0.1
| |-- libsharpyuv.so.0.0.1
| |-- libwebp.a
| |-- libwebp.la
| |-- libwebp.so -> libwebp.so.7.1.8
| |-- libwebp.so.7 -> libwebp.so.7.1.8
| |-- libwebp.so.7.1.8
| |-- libwebpdecoder.a
| |-- libwebpdecoder.la
| |-- libwebpdecoder.so -> libwebpdecoder.so.3.1.8
| |-- libwebpdecoder.so.3 -> libwebpdecoder.so.3.1.8
| |-- libwebpdecoder.so.3.1.8
| |-- libwebpdemux.a
| |-- libwebpdemux.la
| |-- libwebpdemux.so -> libwebpdemux.so.2.0.14
| |-- libwebpdemux.so.2 -> libwebpdemux.so.2.0.14
| |-- libwebpdemux.so.2.0.14
| |-- libwebpmux.a
| |-- libwebpmux.la
| |-- libwebpmux.so -> libwebpmux.so.3.0.13
| |-- libwebpmux.so.3 -> libwebpmux.so.3.0.13
| |-- libwebpmux.so.3.0.13
| `-- pkgconfig
| |-- libsharpyuv.pc
| |-- libwebp.pc
| |-- libwebpdecoder.pc
| |-- libwebpdemux.pc
| `-- libwebpmux.pc
复制到最终 stage 中
我们需要先强制删除安装 libvips-dev
时自带的 libwebp
相关包。
dpkg --remove --force-depends libwebp-dev libwebp7 libwebpdemux2 libwebpmux3
然后想办法把 so
文件复制过来。那么问题来了,怎么复制?我们的 docker image 要支持多架构,对于 amd64 来说共享库的目录是 /usr/lib/x86_64-linux-gnu/
对于 arm64 则是 /usr/lib/aarch64-linux-gnu/
也许你会想,那么还不简单,uname -m
对应架构,没错,可惜 Dockerfile
并不支持这么用,例如如果你想尝试用如下指令的话:
COPY --from=libwebp /build/usr/lib/* /usr/lib/$(uname -m)-linux-gnu/
是不可用的。
那我们投机取巧一下,先复制到临时目录,然后 RUN 就可以啦。要注意 /build/usr/lib/*
结尾的 *
以及最后的 ldconfig
指令。
COPY --from=libwebp /build/usr/lib/* /usr/lib/temp-linux-gnu/
RUN mv /usr/lib/temp-linux-gnu/* /usr/lib/$(uname -m)-linux-gnu/ && ldconfig
完整参考 Dockerfile
FROM golang:1.21-bookworm as builder
ARG IMG_PATH=/opt/pics
ARG EXHAUST_PATH=/opt/exhaust
RUN apt update && apt install --no-install-recommends libvips-dev -y && mkdir /build
COPY go.mod /build
RUN cd /build && go mod download
COPY . /build
RUN cd /build && sed -i "s|.\/pics|${IMG_PATH}|g" config.json \
&& sed -i "s|\"\"|\"${EXHAUST_PATH}\"|g" config.json \
&& sed -i 's/127.0.0.1/0.0.0.0/g' config.json \
&& go build -ldflags="-s -w" -o webp-server .
FROM debian:bookworm-slim as libwebp
RUN apt update && apt install -y wget gcc make autoconf automake libtool libgif-dev \
libjpeg-dev libjpeg62-turbo libjpeg62-turbo-dev libpng-dev libpng-tools libpng16-16 libtiff-dev libtiff6 libtiffxx6
RUN mkdir libwebp && mkdir -p /build/usr && mkdir /build/usr/lib/ && cd libwebp && \
wget https://chromium.googlesource.com/webm/libwebp/+archive/refs/heads/1.3.2.tar.gz && \
tar xf 1.3.2.tar.gz && rm -f 1.3.2.tar.gz && \
./autogen.sh && \
./configure --prefix=/build/usr --libdir=/build/usr/lib --enable-everything && \
make && make install
FROM debian:bookworm-slim
RUN apt update && apt install --no-install-recommends libvips ca-certificates libjemalloc2 libtcmalloc-minimal4 -y && rm -rf /var/lib/apt/lists/* && rm -rf /var/cache/apt/archives/*
# for CVE-2023-4863
RUN dpkg --remove --force-depends libwebp-dev libwebp7 libwebpdemux2 libwebpmux3
COPY --from=libwebp /build/usr/lib/* /usr/lib/temp-linux-gnu/
RUN mv /usr/lib/temp-linux-gnu/* /usr/lib/$(uname -m)-linux-gnu/ && ldconfig
COPY --from=builder /build/webp-server /usr/bin/webp-server
COPY --from=builder /build/config.json /etc/config.json
WORKDIR /opt
VOLUME /opt/exhaust
CMD ["/usr/bin/webp-server", "--config", "/etc/config.json"]
类似的,我们在 WebP Cloud Services 上也进行了类似的 Patch,减少漏洞对于我们系统的影响。
References
WebP Cloud Services 团队是一个来自上海和赫尔辛堡的三人小团队,由于我们不融资,且没有盈利压力 ,所以我们会坚持做我们认为正确的事情,力求在我们的资源和能力允许范围内尽量把事情做到最好, 同时也会在不影响对外提供的服务的情况下整更多的活,并在我们产品上实践各种新奇的东西。
如果你觉得我们的这个服务有意思或者对我们服务感兴趣,欢迎登录 WebP Cloud Dashboard 来体验,如果你好奇它还有哪些神奇的功能,可以来看看我们的文档 WebP Cloud Services Docs,希望大家玩的开心~
Discuss on Hacker News