- 将 7 个文档中的 mac 绝对路径链接(file:///Users/qingsong/...)转换为仓库相对路径, 并修正错误目标:aibox 入口 main.py → aibox.py、pymsg C++ 实现 → libmsg/inc/us/Msg.hpp、 bot4cj cpp/cnn → cuda - 主 README 补 liblogc 基础库条目与 confs2 归档说明,安装顺序补 ca - 新增 liblogc / libtry / confs2 / 3d / memdb README - 同步 db2 脚本迁移(db/create_sqlite3.sql → db2/scripts/)导致的失效引用
174 lines
23 KiB
Markdown
174 lines
23 KiB
Markdown
# libmsg 模块安全审计报告
|
||
|
||
**审计日期**: 2026-08-07(第四轮审计)
|
||
**首次审计**: 2026-08-06
|
||
**审计范围**: `libmsg/inc/us/MsgServer.hpp`、`libmsg/inc/us/RpcServer.hpp`、`libmsg/inc/us/Msg.hpp`、`libmsg/inc/us/RpcClient.hpp`、`libmsg/inc/us/AsyncQueue.hpp`、`libmsg/inc/us/Msg_Basic.hpp`、`libmsg/src/Msg_Basic.cpp`
|
||
**代码版本**: main 分支(基于 e92ef05 进行修复)
|
||
**审计工具**: 人工代码审查 + Qoder Security SAST 原则
|
||
|
||
---
|
||
|
||
## 问题严重等级
|
||
|
||
| 等级 | 说明 | 响应时间 |
|
||
| ----- | --------------------------- | ----- |
|
||
| P0 🔴 | 可导致服务崩溃、DoS 或远程接管、数据发往错误客户端 | 立即修复 |
|
||
| P1 🟠 | 可导致资源耗尽、信息泄露、拒绝服务 | 72小时内 |
|
||
| P2 🟡 | 健壮性/配置问题、校验缺失 | 一周内 |
|
||
| P3 🟢 | 优化建议 | 版本迭代 |
|
||
|
||
---
|
||
|
||
## 修复进度汇总
|
||
|
||
| 审计轮次 | 等级 | 总数 | 已修复 | 待修复 | 修复率 |
|
||
| -------------------- | ------ | ------ | ------ | ----- | -------- |
|
||
| 第一轮 (2026-08-06) | P0 | 1 | 1 | 0 | 100% |
|
||
| 第一轮 (2026-08-06) | P1 | 1 | 1 | 0 | 100% |
|
||
| 第一轮 (2026-08-06) | P2 | 1 | 1 | 0 | 100% |
|
||
| 第二轮 (2026-08-07) | P0 | 1 | 1 | 0 | 100% |
|
||
| 第二轮 (2026-08-07) | P2 | 4 | 4 | 0 | 100% |
|
||
| 第三轮 (2026-08-07) | P1 | 1 | 1 | 0 | 100% |
|
||
| 第三轮 (2026-08-07) | P2 | 1 | 1 | 0 | 100% |
|
||
| 第三轮 (2026-08-07) | P3 | 1 | 1 | 0 | 100% |
|
||
| **第四轮 (2026-08-07)** | **P1** | **1** | **1** | **0** | **100%** |
|
||
| **第四轮 (2026-08-07)** | **P2** | **2** | **2** | **0** | **100%** |
|
||
| **第四轮 (2026-08-07)** | **P3** | **2** | **2** | **0** | **100%** |
|
||
| **合计** | **—** | **16** | **16** | **0** | **100%** |
|
||
|
||
|
||
|
||
---
|
||
|
||
## 已解决发现(16 项,100% 修复)
|
||
|
||
> 以下全部发现的根因分析、触发场景与修复说明已作为 `[libmsg-audit]` 注释合并到源码,便于在代码处直接对照审计结论。源码位置:`libmsg/inc/us/{MsgServer,Msg,Msg_Basic,RpcServer,RpcClient,AsyncQueue}.hpp`(在源码中搜索 `[libmsg-audit]` 即可定位到各修复点)。
|
||
|
||
| 发现 | 等级 | 轮次 | 源码位置 | CWE | 修复摘要 |
|
||
| ---- | ----- | --- | ------------------------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------- |
|
||
| P0-1 | P0 🔴 | 第一轮 | MsgServer.hpp: broadcast / reply / \_remove_client | CWE-362 | 持 per-connection send_lock 再 close,防 fd 关闭后被 OS 复用导致数据发往错误客户端 |
|
||
| P0-2 | P0 🔴 | 第二轮 | MsgServer.hpp: \_close_all_clients | CWE-362 | 批量关闭路径同样持 send_lock 后 shutdown+close,修复第一轮只覆盖单路径的竞态回归 |
|
||
| P1-1 | P1 🟠 | 第一轮 | MsgServer.hpp: \_worker_loop / \_handle_client;Msg.hpp: recvExactDeadline | CWE-400 | workers>0 时 recv 移交 worker 线程,事件循环不再阻塞,防 Slowloris DoS |
|
||
| P1-2 | P1 🟠 | 第三轮 | MsgServer.hpp: \_accept_client | CWE-400 | 新连接设置 SO_SNDTIMEO=5s,慢客户端不读数据时 send 超时抛异常,防服务级 DoS |
|
||
| P1-3 | P1 🟠 | 第四轮 | MsgServer.hpp: ConnectionLock / reply / broadcast / \_remove_client | CWE-362 | 引入 atomic active 标志,close 前设为 false,彻底消除 reply/broadcast 与 \_remove_client 的残余竞态 |
|
||
| P2-1 | P2 🟡 | 第一轮 | RpcServer.hpp: \_sanitize_error | CWE-209 | 脱敏正则扩展为 `/\S+(?:/\S*)*`,覆盖含特殊字符路径,防内部路径泄露 |
|
||
| P2-2 | P2 🟡 | 第二轮 | Msg.hpp: pmsg_recv(int) 注释警告 | CWE-400/672 | 文档标注 SO_RCVTIMEO 前置条件,推荐 deadline 模式,防误用永久阻塞(说明并入 P2-3 文档) |
|
||
| P2-3 | P2 🟡 | 第二轮 | Msg.hpp / MsgServer.hpp / Rpc*.hpp / AsyncQueue.hpp 各入口 | CWE-20 | 新增 validateTimeout / validatePort 及全量配置边界校验,拒绝非法输入 |
|
||
| P2-4 | P2 🟡 | 第二轮 | Msg.hpp: isValidUtf8 | CWE-20 | 接收路径新增完整 UTF-8 校验,与 Python decode('utf-8') 对齐 |
|
||
| P2-5 | P2 🟡 | 第二轮 | MsgServer.hpp: 构造函数 | CWE-20 | 配置项范围校验(已并入 P2-3):recv_timeout / max_connections / max_queue_size / workers / poll_timeout / listen_backlog |
|
||
| P2-6 | P2 🟡 | 第三轮 | MsgServer.hpp: reply | CWE-703 | reply 发送失败标记 \_failed,由主循环统一清理,与 broadcast 一致 |
|
||
| P2-7 | P2 🟡 | 第四轮 | MsgServer.hpp: \_server_fd | CWE-362/662 | \_server_fd 改为 std::atomic<int>,消除 stop() 与 \_event_loop 数据竞争 UB |
|
||
| P2-8 | P2 🟡 | 第四轮 | MsgServer.hpp: start | CWE-20 | start() 校验 on_message 非空,防 bad_function_call |
|
||
| P3-1 | P3 🟢 | 第三轮 | RpcClient.hpp: call | CWE-20 | 调用 as_bool() 前校验 success 为 bool,类型不符抛 RpcError |
|
||
| P3-2 | P3 🟢 | 第四轮 | RpcServer.hpp: \_dispatch | CWE-209 | \_route 缺失 vs 类型不符返回不同错误信息 |
|
||
| P3-3 | P3 🟢 | 第四轮 | MsgServer.hpp: \_accept_client | — | setsockopt 移到加入 \_clients 之前,先完成 socket 配置再暴露给其他线程 |
|
||
|
||
|
||
|
||
---
|
||
|
||
## ✅ 已有安全机制(更新后)
|
||
|
||
| 机制 | 位置 | 说明 |
|
||
| -------------------------------- | ----------------------------------------------- | ---------------------------------------------- |
|
||
| 消息大小上限 64 MiB | `Msg_Basic.hpp` `kMaxMsgSize` | 防止超大消息耗尽内存 |
|
||
| deadline 模式 recv 超时 | `Msg.hpp` `recvFrameDeadline` | header+payload 共享总超时,防 Slowloris |
|
||
| 入口参数边界校验 | `Msg.hpp/MsgServer.hpp/AsyncQueue.hpp/Rpc*.hpp` | timeout/port/配置项全范围校验,拒绝非法输入 |
|
||
| UTF-8 载荷校验 | `Msg.hpp` `isValidUtf8()` | 与 Python decode('utf-8') 对齐,拒绝非法字节序列 |
|
||
| 最大连接数限制 | `MsgServer.hpp` `max_connections=1000` | 超限拒绝新连接 |
|
||
| 有界任务队列 | `MsgServer.hpp` `max_queue_size=1000` | 队列满时断开连接,防 OOM |
|
||
| per-connection 发送锁 + active 标志 | `MsgServer.hpp` `ConnectionLock` | reply/broadcast 线程安全防帧交错 + active 检查防 fd 复用后发送 |
|
||
| 服务端发送超时 SO_SNDTIMEO | `MsgServer.hpp` `_accept_client()` | 慢客户端不读数据时 send 超时抛异常,防拒绝服务(P1-2) |
|
||
| reply() 失败标记 failed | `MsgServer.hpp` `reply()` | 与 broadcast 一致,失败连接由主循环清理(P2-6) |
|
||
| RpcClient success 类型校验 | `RpcClient.hpp` `call()` | 非 bool 时抛 RpcError,而非未捕获的 boost 异常(P3-1) |
|
||
| \_close_all_clients 批量关闭也持锁 | `MsgServer.hpp` `_close_all_clients()` | 修复批量关闭路径的竞态(P0-2) |
|
||
| **新增**: ConnectionLock active 标志 | `MsgServer.hpp` `ConnectionLock::active` | reply/broadcast 获取锁后检查 active,彻底消除残余竞态(P1-3) |
|
||
| **新增**: \_server_fd atomic 访问 | `MsgServer.hpp` `std::atomic<int> _server_fd` | 消除 stop() 与 \_event_loop 的数据竞争 UB(P2-7) |
|
||
| **新增**: start() 空回调校验 | `MsgServer.hpp` `start()` | 防止 bad_function_call 异常(P2-8) |
|
||
| **新增**: \_accept_client 先配置后注册 | `MsgServer.hpp` `_accept_client()` | socket 选项在加入 \_clients 前设置完整(P3-3) |
|
||
| 同一连接消息串行 | `MsgServer.hpp` `_busy` 集合 | 回调执行中暂停该连接 select 监听 |
|
||
| JSON 解析深度限制 | `RpcServer.hpp` `opts.max_depth=32` | 防深度嵌套 JSON 导致栈溢出 |
|
||
| 异常信息脱敏 | `RpcServer.hpp` `_sanitize_error()` | 过滤绝对路径,完整异常由 on_error 钩子记录 |
|
||
| RpcClient 响应格式校验 | `RpcClient.hpp` | 校验 success 字段,非法响应抛 RpcError |
|
||
| worker 线程异常隔离 | `MsgServer.hpp` `_worker_loop()` | handler 异常仅断开该连接,不影响服务 |
|
||
| select FD_SETSIZE 检查 | `MsgServer.hpp` `_accept_client()` | fd >= FD_SETSIZE 时拒绝连接,防 select 越界 |
|
||
| TCP_NODELAY | `MsgServer.hpp` `_accept_client()` | 新连接禁用 Nagle 算法,降低小包延迟 |
|
||
| MSG_NOSIGNAL 兼容 | `Msg.hpp` | macOS 兼容,防止 send 到关闭连接触发 SIGPIPE |
|
||
| AsyncQueue 背压保护 | `AsyncQueue.hpp` `max_queue_size` | 队列满时丢最旧数据,防内存无限增长 |
|
||
| AsyncQueue fail-safe | `AsyncQueue.hpp` | handler 异常触发 on_error,不传播到业务线程 |
|
||
|
||
---
|
||
|
||
## 待修复 / 已知限制(架构层面,非代码缺陷)
|
||
|
||
| # | 问题 | 优先级 | 说明 |
|
||
| ---- | ----------------------------------------------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| L-1 | 无认证/鉴权机制 | P0(已缓解) | 仅依赖绑定 127.0.0.1 网络层隔离,任意本地进程可调用所有路由。设计如此,内网微服务信任模型。 |
|
||
| L-2 | 无 TLS 加密传输 | P1 | 内网明文 TCP,进程间通信可被本地 root 用户抓包。如跨主机部署需增加 TLS 层。 |
|
||
| L-3 | 同步模式(workers=0)仍在主线程阻塞 recv | P2 | 无线程池时无法并发,Slowloris 防护依赖 recv_timeout 截止时间(10秒)。建议生产环境使用 workers>0。 |
|
||
| L-4 | select 模型上限 FD_SETSIZE(通常 1024) | P2 | 高并发场景建议改用 epoll/kqueue,或在 fd 超限时告警/拒绝。已在 \_accept_client 加检查防止越界。 |
|
||
| L-5 | 安全事件无结构化日志 | P3 | 超时、超大消息、UTF-8 校验失败、JSON 解析失败等仅 fprintf(stderr),无可观测性。建议接入结构化日志。 |
|
||
| L-6 | pmsg_recv(int) 单参数版本仍依赖外部超时设置 | P3 | 已添加文档警告,推荐使用 deadline 模式。考虑未来版本弃用单参数版本或内部设置安全默认超时。 |
|
||
| L-7 | AsyncQueue 关闭时 flush 失败数据只记 on_error | P3 | \_flush_all() 中 handler 失败后数据不重试,符合非关键路径设计,但应确保 on_error 有持久化/告警机制。 |
|
||
| L-8 | 半连接(只发部分帧头)仍可占用一个 worker 线程 recv_timeout 秒 | P2 | workers>0 时消息接收在 worker 线程完成,慢连接可占用 worker 最多 recv_timeout(默认10秒)。数量受 max_connections 与 recv_timeout 有界约束,已缓解。可用更小 recv_timeout 或独立接收线程池进一步收紧。 |
|
||
| L-9 | pmsg_send 发送端不校验 UTF-8,与 Python 版 encode('utf-8') 不对称 | P3 | 接收端已在 pmsg_recv 校验 UTF-8(P2-4),非法载荷会被远端断开。发送端未校验,若业务传入二进制可能被远端拒绝。若存在纯二进制传输场景,发送端校验会破坏兼容,故暂不强制,仅记录。 |
|
||
| L-10 | pmsg_send 公共 API 依赖 SO_SNDTIMEO | P3 | sendAll() 在 send() 返回 EAGAIN 时抛超时异常,但前提是 socket 已设置 SO_SNDTIMEO。已添加文档警告,MsgClient 和 MsgServer 内部均已设置。直接使用 pmsg_send 的外部调用方需自行设置。 |
|
||
| L-11 | MsgServer 未设置 TCP keepalive | P3 | 客户端崩溃(不发送 FIN)时连接会残留直到 select 检测异常或 send 失败。建议生产环境设置 SO_KEEPALIVE 以更快检测死连接。 |
|
||
| L-12 | \_remove_client 同步模式下无总超时限制 | P3 | 同步模式下 \_handle_client 中 pmsg_recv 有 recv_timeout 限制,但回调执行无超时。慢回调会阻塞事件循环。建议将慢操作移至线程池模式或业务层自行限时。 |
|
||
|
||
---
|
||
|
||
## 变更记录
|
||
|
||
### 2026-08-07(第四轮审计修复)
|
||
|
||
**代码变更文件**:
|
||
|
||
| 文件 | 变更内容 |
|
||
| --------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| [MsgServer.hpp](../../libmsg/inc/us/MsgServer.hpp) | **P1修复**: 引入 `ConnectionLock` 结构(mutex + atomic active),`reply()`/`broadcast()` 获取锁后检查 `active`,`_remove_client()`/`_close_all_clients()` close 前设置 `active=false`,彻底消除残余竞态(P1-3);**P2修复**: `_server_fd` 改为 `std::atomic<int>`,所有访问使用 `.load()`/`.store()`/`.exchange()`(P2-7);**P2修复**: `start()` 校验 `on_message` 非空(P2-8);**P3修复**: `_accept_client()` 中 setsockopt 移到加入 `_clients` 之前(P3-3) |
|
||
| [RpcServer.hpp](../../libmsg/inc/us/RpcServer.hpp) | **P3修复**: `_dispatch()` 区分 `_route` 字段缺失和类型不符的错误信息(P3-2) |
|
||
| [Msg.hpp](../../libmsg/inc/us/Msg.hpp) | **文档**: `pmsg_send` 添加 SO_SNDTIMEO 前置条件警告(L-10) |
|
||
|
||
### 2026-08-07(第三轮审计修复)
|
||
|
||
**代码变更文件**:
|
||
|
||
| 文件 | 变更内容 |
|
||
| --------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| [MsgServer.hpp](../../libmsg/inc/us/MsgServer.hpp) | **P1修复**: `_accept_client()` 对新连接设置 `SO_SNDTIMEO=5s`,慢客户端不读数据时 send 超时抛异常,防服务级 DoS(P1-2);**P2修复**: `reply()` 发送失败标记 `_failed`,由主循环清理连接(P2-6) |
|
||
| [RpcClient.hpp](../../libmsg/inc/us/RpcClient.hpp) | **P3修复**: `call()` 调用 `as_bool()` 前校验 `success` 字段为 bool,类型不符抛 RpcError(P3-1) |
|
||
|
||
### 2026-08-07(第二轮审计修复)
|
||
|
||
**代码变更文件**:
|
||
|
||
| 文件 | 变更内容 |
|
||
| ----------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||
| [Msg.hpp](../../libmsg/inc/us/Msg.hpp) | 新增 isValidUtf8()/validateTimeout()/validatePort();recvFrameDeadline 添加参数校验和UTF-8校验;openConnection 添加 port/timeout 校验;pmsg_recv(int) 添加UTF-8校验和文档警告;MsgClient 构造/call 添加参数校验 |
|
||
| [MsgServer.hpp](../../libmsg/inc/us/MsgServer.hpp) | **P0修复**: \_close_all_clients() 改为持 send_lock 关闭并 shutdown;构造函数添加全量配置校验 |
|
||
| [AsyncQueue.hpp](../../libmsg/inc/us/AsyncQueue.hpp) | 添加 <stdexcept>/<string> 头文件;构造函数校验 handler 非空、batch_size、flush_interval、poll_timeout 范围 |
|
||
| [RpcClient.hpp](../../libmsg/inc/us/RpcClient.hpp) | 构造函数校验 timeout、retry_interval 范围 |
|
||
| [RpcServer.hpp](../../libmsg/inc/us/RpcServer.hpp) | add_route() 校验 name 非空、handler 非空 |
|
||
|
||
---
|
||
|
||
## 审计结论
|
||
|
||
四轮审计累计发现 **16 个问题,全部已修复(100%)**。
|
||
|
||
- **第一轮(2026-08-06)**: 3 个问题(P0 竞态、P1 Slowloris、P2 脱敏正则)已修复。
|
||
- **第二轮(2026-08-07)**: 5 个问题(P0 批量关闭竞态回归、4 个 P2 健壮性)已修复。
|
||
- **第三轮(2026-08-07)**: 3 个新问题(P1 服务端发送超时缺失、P2 reply 失败未清理、P3 RpcClient success 类型校验)已修复。
|
||
- **第四轮(2026-08-07)**: 5 个新问题(P1 reply/broadcast 残余竞态、P2 \_server_fd 数据竞争、P2 start 空回调校验、P3 \_route 错误信息、P3 setsockopt 顺序)已修复。
|
||
|
||
结合四轮审计结果,libmsg 核心通信层的安全状况良好:
|
||
|
||
- **内存安全**: 无缓冲区溢出、无 use-after-free(fd 生命周期通过 ConnectionLock + shared_ptr + atomic active 严格管理)
|
||
- **DoS 防护**: 64MiB 消息上限、deadline 模式接收超时(防Slowloris)、服务端发送超时 SO_SNDTIMEO(防慢客户端耗尽资源)、max_connections 连接数限制、max_queue_size 队列上限、poll_timeout 防忙轮询、全量参数边界校验
|
||
- **竞态安全**: 所有 fd 关闭路径均持有 per-connection send_mtx 并设置 active=false,reply/broadcast 获取锁后检查 active,**彻底消除 CWE-362 竞态(含正向和反向场景)**;\_server_fd 使用 atomic 消除数据竞争 UB
|
||
- **协议健壮性**: UTF-8 收发端校验与 Python 版对齐、RpcClient 响应字段类型校验统一抛 RpcError、RpcServer \_route 类型校验
|
||
- **异常安全**: worker 线程异常隔离、AsyncQueue fail-safe、Handler 异常不崩溃服务、RPC 错误脱敏、reply/broadcast 失败连接统一清理、start 空回调校验
|
||
|
||
遗留的 L-1~L-12 项为架构层面的已知限制/设计决策,非代码缺陷,可根据实际部署需求决定是否增强。
|