跳过正文

RDB_OPCODE_SLOT_IMPORT short job_name causes server-side heap out-of-bounds read during startup RDB loading

作者
杨全烨
系统软件:操作系统、网络与分布式系统。
目录

https://github.com/valkey-io/valkey/issues/4207 一类安全性问题,上面是issue界面,可以尝试解决一下。

典型的 trust-boundary 长度契约不一致——命令路径强制 job_name 必须是 40 字节, RDB 加载路径却没校验,导致 memcpy(..., 40) 从短 SDS 上越界读。

漏洞本质(从内存布局看)
#

子系统约定
#

CLUSTER_NAMELEN == 40,job name 是固定长度 hex(类似 node id):

char name[CLUSTER_NAMELEN];               /* Unique name for the job, hex
	                                       * string, sha1-size. */
  • Save 路径:写死 40 字节
    rdbSaveRawString(rdb, job->name, CLUSTER_NAMELEN)
  • 命令路径:显式拒绝非 40 字节
    sdslen(...) != CLUSTER_NAMELEN
  • Load 路径(有洞):rdbLoadStringObject() 接受任意长度字符串,原样交给 createSlotImportJob()

崩溃点
#

// 这就是RDB导入的时候造成的问题?
slotMigrationJob *createSlotImportJob(client *c,
                                      clusterNode *source_node,
                                      char *name,
                                      list *slot_ranges) {
    slotMigrationJob *job = zcalloc(sizeof(slotMigrationJob));
    memcpy(job->name, name, CLUSTER_NAMELEN);

当 RDB 里 job_name 只有 1 字节时:

heap:  [sdshdr...]['A']['\0'][ 后续可能是 freelist/相邻分配物 ...]
         ^ objectGetVal()
memcpy 要读 40 字节  越过 SDS 逻辑长度  heap OOB read

目标 job->name[40] 本身合法;问题是源指针没有 40 字节可读数据。 ASan 报的是 read,不是 write——典型 DoS(可靠 crash),不是直接任意写。

攻击面
#

需要把恶意 dump.rdb 放到实例数据目录,并开 cluster-enabled yes。 常见场景:备份投毒、共享存储、错误恢复流程。不是远程未认证协议洞,但仍是启动期可信输入校验失败。

尝试复现问题
#

太神奇了,这是怎么使用AI发现的? 复现路径在issue中描述的非常详细。

步骤 做什么
A 从 unstable 拉新分支
B ASan 复现(确认 crash)
C 按建议加长度校验
D 加回归测试(最好 Tcl,启动期拒载)
E 推到你的 fork quanyeyang/valkey,对 valkey-io/valkey 开 PR,关联 #4207
# 1) ASan 构建
make distclean
make -j"$(nproc)" SANITIZER=address OPTIMIZATION=-O0

# 2) 按 issue 生成 empty.rdb → 插入 opcode 0xF3 短 name → 重算 CRC64
# 3) cluster-enabled 实例加载该 dump.rdb
# 期望:ASan 在 memcpy 处报 heap-buffer-overflow READ