strsep解析sysfs写入内容导致Linux 3.2内核冻结问题排查
排查内核sysfs写入导致的系统冻结问题
兄弟,你遇到的这个系统冻结问题,根源确实在requestDstAddr函数的字符串解析逻辑里——咱们一点点拆解问题,再给你修复方案:
核心问题分析
你用户态Python写入的是类似"12345|678|"的字符串,没有末尾的NUL终止符,但内核态的字符串处理函数(strsep、kstrtol)都要求输入是以NUL结尾的合法C字符串。现在的代码有几个致命问题:
没有给字符串加NUL终止符
你用kmalloc(sizeof(char)*count)分配内存,然后memcpy(localBuff, buff, count),但buff是用户态传过来的原始数据(没有NUL),导致localBuff里的内容没有结束标志。strsep和kstrtol会一直往后读内存,直到碰到NUL,这就会触发越界内存访问,轻则破坏内核数据结构,直接导致系统冻结。没有检查字符串分割和转换的错误
- 如果
strsep返回NULL(比如分割符不对),直接传给kstrtol会引发非法内存访问; - 没有检查
kstrtol的返回值,如果用户传入非数字内容,temp会变成垃圾值,写入requestedSrcIP/requestedSrcPort后可能破坏其他内核数据。
- 如果
内存分配的小细节
虽然GFP_ATOMIC在sysfs场景下没问题,但如果kmalloc失败直接返回-1,不符合内核函数的错误码规范(应该返回-ENOMEM)。
修复后的内核代码示例
ssize_t requestDstAddr( struct device *dev, struct device_attribute *attr, const char *buff, size_t count) { char *token; // 多分配1字节存NUL终止符 char *localBuff = kmalloc(count + 1, GFP_ATOMIC); long int temp; int ret = count; // 默认返回写入的字节数 if(localBuff == NULL) { printk(KERN_ERR "ERROR: kmalloc failed\n"); return -ENOMEM; // 使用标准错误码 } // 拷贝数据并手动添加NUL终止符 memcpy(localBuff, buff, count); localBuff[count] = '\0'; spin_lock(&conntabLock); // 解析源IP,检查每一步错误 token = strsep(&localBuff, "|"); if (!token || kstrtol(token, 10, &temp) != 0) { printk(KERN_ERR "Invalid source IP format\n"); ret = -EINVAL; goto unlock_and_free; } requestedSrcIP = htonl(temp); // 解析源端口,同样检查错误 token = strsep(&localBuff, "|"); if (!token || kstrtol(token, 10, &temp) != 0) { printk(KERN_ERR "Invalid source port format\n"); ret = -EINVAL; goto unlock_and_free; } requestedSrcPort = htons(temp); unlock_and_free: spin_unlock(&conntabLock); kfree(localBuff); return ret; }
额外注意事项
- 你的Python代码末尾多写了一个
|,其实可以去掉,不过修复后的内核代码即使保留也能正确处理; - Linux 3.2内核比较老,记得测试修复后的模块,避免其他兼容性问题;
- 系统冻结后如果能保存
dmesg日志,里面的Oops信息会直接指向越界访问的位置,下次遇到类似问题可以先查这个。
内容的提问来源于stack exchange,提问作者Eloo
相关产品推荐
相关产品推荐

