当我在自己的环境中运行 boron 时,在处理略微畸形的输入时,偶然发现了 libboron(libboron.so.2 版本 2.0.8)中的 2 个堆缓冲区溢出。这已在 Mac (x86_64) 和 Linux (x86_64) 上正式测试过:
git clone https://github.com/0branch/boron.git cd boron ./configure && make sudo make install && sudo ldconfig
## (CVE-2023-40294) i_parse_blk.c 中 ur_parseBlockI 的堆缓冲区溢出:
https://github.com/0branch/boron/blob/e98ed6cbc7911cf31a6e4ac8a0b00fd7c224e807/urlan/i_parse_blk.c#L21
首先,我针对导致崩溃的文件运行了 boron:```
$ ./boron ur_parseBlockI_overflow.b
malloc(): invalid size (unsorted)
zsh: IOT instruction ./boron ur_parseBlockI_overflow.b
输出的结果让我相信是堆溢出破坏了 unsorted bin 中的堆块,因此我使用 AddressSanitizer 和调试符号编译该项目进行验证:
VER=2.0.8
DESTDIR ?= /usr/local BIN_DIR=$(DESTDIR)/bin LIB_DIR=$(DESTDIR)/lib INC_DIR=$(DESTDIR)/include/boron MAN_DIR=$(DESTDIR)/share/man/man1 VIM_DIR=$(DESTDIR)/share/vim/vimfiles/syntax
OS := $(shell uname)
CFLAGS = -pipe -pedantic -Wall -W -Iinclude -Iurlan -Ieval -Isupport -g -fsanitize=address -DDEBUG #CFLAGS += -O3 -DNDEBUG #CFLAGS += -g -DDEBUG
ifeq ($(OS), Darwin) CFLAGS += -std=c99 AR_LIB = libtool -static -o else CFLAGS += -std=gnu99 -fPIC AR_LIB = ar rc ifneq (,$(wildcard /usr/lib64/libc.so)) LIB_DIR=$(DESTDIR)/lib64 else ifneq (,$(wildcard /usr/lib/x86_64-linux-gnu/.)) LIB_DIR=$(DESTDIR)/lib/x86_64-linux-gnu endif endif
CONFIG := $(shell cat config.opt) ifneq (,$(findstring _STATIC,$(CONFIG))) STATIC_LIB = true endif
LIBS := -lm
ODIR = .obj
OBJ_FN = env.o array.o binary.o block.o coord.o date.o path.o
string.o context.o gc.o serialize.o tokenize.o
vector.o parse_block.o parse_string.o
OBJ_FN += str.o mem_util.o quickSortIndex.o fpconv.o
OBJ_FN += os.o boron.o port_file.o wait.o
ifneq (,$(findstring _HASHMAP,$(CONFIG)))
OBJ_FN += hashmap.o
endif
ifneq (,$(findstring _RANDOM,$(CONFIG)))
OBJ_FN += well512.o random.o
endif
ifneq (,$(findstring _SOCKET,$(CONFIG)))
OBJ_FN += port_socket.o
endif
ifneq (,$(findstring _THREAD,$(CONFIG)))
OBJ_FN += port_thread.o
ifeq ($(OS), Linux)
LIBS += -lpthread
endif
endif
LIB_OBJS = $(addprefix $(ODIR)/,$(OBJ_FN))
MAIN_FN = main.o ifneq (,$(findstring _LINENOISE,$(CONFIG))) MAIN_FN += linenoise.o else EXE_LIBS += -lreadline -lhistory endif ifneq (,$(findstring _COMPRESS=1,$(CONFIG))) LIBS += -lz endif ifneq (,$(findstring _COMPRESS=2,$(CONFIG))) LIBS += -lbz2 endif EXE_OBJS = $(addprefix $(ODIR)/,$(MAIN_FN))
ifdef STATIC_LIB BORON_LIB = libboron.a EXE_LIBS += $(LIBS) else ifeq ($(OS), Darwin) BORON_LIB = libboron.dylib else BORON_LIB = libboron.so.$(VER) endif
$(ODIR)/%.o: urlan/%.c cc -c $(CFLAGS) $(CONFIG) $< -o $@ $(ODIR)/%.o: support/%.c cc -c $(CFLAGS) $(CONFIG) $< -o $@ $(ODIR)/%.o: eval/%.c cc -c $(CFLAGS) $(CONFIG) $< -o $@
boron: $(EXE_OBJS) $(BORON_LIB) cc $^ -o $@ $(EXE_LIBS) -g -fsanitize=address
$(ODIR)/os.o: unix/os.c cc -c $(CFLAGS) $(CONFIG) $< -o $@
$(EXE_OBJS): | $(ODIR) $(LIB_OBJS): | $(ODIR) $(ODIR): mkdir -p $@
$(BORON_LIB): $(LIB_OBJS) ifdef STATIC_LIB $(AR_LIB) $@ $^ ranlib $@ else ifeq ($(OS), Darwin) libtool -dynamiclib -o $@ $^ -install_name @rpath/$(BORON_LIB) $(LIBS) else cc -o $@ -shared -g -fsanitize=address -Wl,-soname,libboron.so.2 $^ $(LIBS) ln -sf $(BORON_LIB) libboron.so.2 ln -sf $(BORON_LIB) libboron.so endif
.PHONY: clean install uninstall install-dev uninstall-dev
clean: rm -f boron $(BORON_LIB) $(LIB_OBJS) $(EXE_OBJS) ifndef STATIC_LIB rm -f libboron.so* endif rmdir $(ODIR)
install: mkdir -p $(BIN_DIR) $(LIB_DIR) $(MAN_DIR) ifndef STATIC_LIB ifeq ($(OS), Darwin) install_name_tool -id $(LIB_DIR)/libboron.dylib libboron.dylib install_name_tool -change libboron.dylib $(LIB_DIR)/libboron.dylib boron install -m 644 libboron.dylib $(LIB_DIR) else install -m 755 -s $(BORON_LIB) $(LIB_DIR) ln -s $(BORON_LIB) $(LIB_DIR)/libboron.so.2 endif endif install -s -m 755 boron $(BIN_DIR) gzip -c -n doc/boron.troff > doc/boron.1.gz install -m 644 doc/boron.1.gz $(MAN_DIR)
uninstall: rm -f $(BIN_DIR)/boron $(MAN_DIR)/boron.1 ifndef STATIC_LIB rm -f $(LIB_DIR)/$(BORON_LIB) ifneq ($(OS), Darwin) rm -f $(LIB_DIR)/libboron.so.2 endif endif
install-dev:
mkdir -p $(INC_DIR) $(LIB_DIR)
sed -e 's~"urlan.h"<boron/urlan.h>' include/boron.h >boron.tmp
install -m 644 boron.tmp $(INC_DIR)/boron.h
rm boron.tmp
install -m 644 include/urlan.h $(INC_DIR)
install -m 644 include/urlan_atoms.h $(INC_DIR)
ifdef STATIC_LIB install -m 644 $(BORON_LIB) $(LIB_DIR) endif ifneq ($(OS), Darwin) mkdir -p $(VIM_DIR) install -m 644 doc/boron.vim $(VIM_DIR) ifndef STATIC_LIB ln -s $(BORON_LIB) $(LIB_DIR)/libboron.so endif endif
uninstall-dev: ifdef STATIC_LIB rm -f $(LIB_DIR)/$(BORON_LIB) endif ifneq ($(OS), Darwin) ifndef STATIC_LIB rm -f $(LIB_DIR)/libboron.so endif rm -f $(VIM_DIR)/boron.vim endif
rm -f $(INC_DIR)/boron.h $(INC_DIR)/urlan.h $(INC_DIR)/urlan_atoms.h
rmdir $(INC_DIR)
再次对 ur_parseBlockI_overflow.b 执行 boron 会产生以下 ASAN 输出,确认堆缓冲区溢出: