使用带偏移的sscanf读取内核设备store函数缓冲区时进程被杀死如何解决
问题成因
- sysfs 缓冲区无字符串结束符:sysfs 的 store 回调传入的
buf是原始字节缓冲区,仅保证count长度内的内容有效,不会自动追加\0字符串结束符。你直接将该缓冲区传入sscanf处理时,sscanf会一直向后查找结束符,第一行处理完成后偏移指针,很容易访问到count边界外的非法内存,触发内核越界检查,直接杀死触发操作的用户进程,也就是你看到的「Killed」输出。 - 缺少边界校验逻辑:你没有在每次偏移指针前校验当前地址是否超出了本次写入的总长度边界
buf + count,一旦偏移后地址越界,后续内存访问会直接触发内核 oops。 - 不符合 sysfs 写入规范:sysfs 设计上默认单次
write调用对应一次完整的属性更新,如果你在用户空间拆分了多次write写入多行规则,每次 store 调用只能拿到单次写入的部分内容,偏移后自然会访问非法地址。
修复方案
- 先将本次写入的内容拷贝到内核自有缓冲区,手动补充结束符,避免结束符缺失问题:
// 分配内核缓冲区,多分配1字节存结束符 char *kern_buf = kzalloc(count + 1, GFP_KERNEL); if (!kern_buf) return -ENOMEM; memcpy(kern_buf, buf, count); // 后续所有解析逻辑都基于kern_buf处理,不要直接操作传入的buf
- 补充边界校验,解析时严格限制访问范围:
char *curr = kern_buf; // 每次循环前校验当前指针不超出总长度 while (curr < kern_buf + count) { int read_cnt = sscanf(curr, "%s%s%s%s%s%s%s%s%s%n", rule_name, direction_string, src_ip, dst_ip, src_port_string, dst_port_string, protocol_string, ack_string, action_string, &offset); if (read_cnt != 9) break; // 此处添加你的行处理逻辑 // 偏移指针 curr += offset; // 跳过换行、空格等空白字符,避免下一次解析异常 while (curr < kern_buf + count && (*curr == '\n' || *curr == '\r' || *curr == ' ')) { curr++; } } // 用完释放缓冲区 kfree(kern_buf);
- 调整用户空间逻辑,将所有规则内容通过单次
write调用一次性写入sysfs节点,不要拆分多次写入。 - 可选优化:给
sscanf的%s占位符添加长度限制,比如rule_name缓冲区大小为32时就写成%31s,避免字段过长溢出缓冲区。
内容的提问来源于stack exchange,提问作者QueryMan
相关产品推荐
相关产品推荐

