Skip to content

Bug: DataMap::sub_iterator 中 ulong/long 混用导致潜在的越界访问 #54

@lanlanxiyiji

Description

@lanlanxiyiji

问题描述

DataMap::sub_iterator() 中计算起始索引时混用有符号/无符号类型,当 cnt > idxst 为负值,隐式转换为 ulong 后发生回绕,导致循环访问超出 m_entrys 数组边界。

代码位置

文件: libdkapture/so/data-map.cpp
函数: DataMap::sub_iterator()
行号: 121-131

int DataMap::sub_iterator(ulong idx, void *buf, size_t bsz) const                                                                                                                                                                                                                       
{                                                                
    idx &= (m_ent_cnt - 1);                                                                                                                                                                                                                                                             
    idx += m_ent_cnt;      
    const AddrEntry &entry = m_entrys[idx];                                                                                                                                                                                                                                             
    ulong cnt = entry.dsz;                 
    DKapture::DataType dt = KEY_DT(entry.hash);                                                                                                                                                                                                                                         
    long st = idx - cnt;          // <--- 有符号 long                                                                                                                                                                                                                                   
    DEBUG(0, "sub_iterator st: %lu cnt: %lu bsz: %lu", st, cnt, bsz);                                                                                                                                                                                                                   
    int ret = 0;                                                                                                                                                                                                                                                                        
    for (ulong i = st; i < idx; i++)  // <--- 无符号 ulong,隐式转换                                                                                                                                                                                                                    
    {                                                                                                                                                                                                                                                                                   
        if (KEY_DT(m_entrys[i].hash) != dt)                                                                                                                                                                                                                                             
        {                                                                                                                                                                                                                                                                               
            continue;                                                                                                                                                                                                                                                                   
        }                                                                                                                                                                                                                                                                               
        // ... 访问 m_entrys[i]                                                                                                                                                                                                                                                         
    }                                                                                                                                                                                                                                                                                   
}    
                                                                                                                                                                                                                                                                                        
触发条件        
                                                                                                                                                                                                                                                                                        
cnt(即 entry.dsz)大于 idx 时即可触发。虽然正常场景下 dsz 通常较小,但如果:                                                                                                                                                                                                           
- 共享内存中的 AddrEntry 数据被意外破坏(如其他进程写入)                                                                                                                                                                                                                               
- push() 传入异常大的 dsz 值                                                                                                                                                                                                                                                            
- 并发场景下读到半写入状态的数据
                                                                                                                                                                                                                                                                                        
则 st = idx - cnt 为负,for (ulong i = st; ...) 中 st 回绕为接近 ULONG_MAX 的极大值。此时循环条件 i < idx 几乎恒为 false,循环体不会执行;但若因某些巧合条件成立,则会访问远超出 m_entrys 数组范围的内存。                                                                              
                                                                                                                                                                                                                                                                                        
预期行为                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                        
即使 cnt > idx,也应安全处理,不依赖无符号回绕来"意外跳过"循环。                                                                                                                                                                                                                        
 
建议修复                                                                                                                                                                                                                                                                                
                
在计算 st 前添加前置保护,将 cnt 限制在有效范围内:                                                                                                                                                                                                                                     
                
ulong cnt = entry.dsz;                                                                                                                                                                                                                                                                  
if (cnt > idx) {                                                                                                                                                                                                                                                                        
    cnt = idx;                                                                                                                                                                                                                                                                          
}                                                                                                                                                                                                                                                                                       
long st = idx - cnt;                                                                                                                                                                                                                                                                    
                                                                                                                                                                                                                                                                                        
或统一使用有符号类型:
                                                                                                                                                                                                                                                                                        
long cnt = entry.dsz;                                                                                                                                                                                                                                                                   
if (cnt < 0) cnt = 0;
if (cnt > (long)idx) cnt = idx;                                                                                                                                                                                                                                                         
long st = (long)idx - cnt;                                                                                                                                                                                                                                                              
for (long i = st; i < (long)idx; i++)                                                                                                                                                                                                                                                   
                                                                                                                                                                                                                                                                                        
环境信息                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                        
- 版本: 当前 master(commit bf1c3e4 及之后)                                                                                                                                                                                                                                            
- 架构: 所有平台(x86_64、ARM64、Loong64、sw64)
- 编译器: 任何支持 C++17 的编译器均可复现此问题                                                                                                                                                                                                                                         
                                                                                                                                                                                                                                                                                        
附加说明                                                                                                                                                                                                                                                                                
                                                                                                                                                                                                                                                                                        
该问题在 DEBUG 日志中可能被掩盖——DEBUG(0, "sub_iterator st: %lu ...", st, ...) 使用 %lu 打印 long 类型,若 st 为负值,输出将表现为一个极大的正数,增加调试难度。                                                                                                                        
                
--- 

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions