问题描述
协作(Loro CRDT)模式下,一个畸形/恶意远端光标载荷即可让本端在渲染路径上稳定 SIGSEGV,且 catch (string) 挡不住段错误。
edit_modify_rep::resolve_cursor(src/Edit/Modify/edit_collab.cpp,引入 commit 188dd26 [0791] Collab: Structured Cursor)解析远端光标 off 字段时:
int at_pos = search_forwards ("@", off_field);
string core_off= off_field;
if (at_pos >= 0) {
core_off= off_field (0, at_pos); // at_pos==0 时 core_off 为空串
...
}
char head= core_off[0]; // ← 无守卫
off_field == "@O"(或 "@C" 等以 @ 开头的 off 字段,例如对端发来 peer:counter:@O)时 at_pos == 0 → core_off == "";
- lolly 空串的缓冲区指针为 NULL(
string_rep::string_rep:a((n==0) ? ((char*)NULL) : ...)),string::operator[] 无边界检查 → 空指针读 → SIGSEGV。
触达路径(每帧重绘)
- 网络层:
loro_collab.cpp:379 → ed->set_remote_cursor (peer, payload)(载荷来自对端,仅按空格切 3 组、按冒号切字段,无语义校验);
- 缓存:坏条目存入
remote_cursors;
- 渲染:
edit_repaint.cpp:212 → get_remote_cursors() 对每个条目调 resolve_cursor —— 每次重绘都会执行,一个坏条目让本端每一帧都崩,不是一次性崩溃。
版本不匹配(如旧版客户端发 "@O" 锚点格式)或畸形/恶意 peer 均可触发。
复现(已验证)
--loro=y 构建下,直接调用文件静态 resolve_cursor 的单测(SIGSEGV guard + 断言):
#define LORO_ENABLED
#include "base.hpp"
#include "../../../src/Edit/Modify/edit_collab.cpp" // 引入文件静态 resolve_cursor
static bool resolve_cursor_crashes (string off_field) {
tree buf (moebius::DOCUMENT); loro_shadow doc; array<linear_item> items;
mogan_tree_id tid{0, 0};
// signal(SIGSEGV) + setjmp/longjmp guard
resolve_cursor (tid, off_field, buf, doc, items);
return g_crashed;
}
// QVERIFY (!resolve_cursor_crashes (string ("@O"))); // 当前 main 上 crashed == true
实测输出(Debian 13,x86_64,d2242e3e5):
PASS : TestCollabCursorPayload::initTestCase()
FAIL! : TestCollabCursorPayload::test_at_sign_only_off_field() '!crashed' returned FALSE. ()
即 resolve_cursor(tid, "@O", ...) 触发 SIGSEGV。等价的黑盒路径:set_remote_cursor("p1", "0:0:@O 0:0:@O 0:0:@O") 后触发一次重绘。
建议
resolve_cursor 在 char head= core_off[0]; 前补空串守卫(if (N (core_off) == 0) return path ();),与函数开头对 off_field 的守卫保持一致;同时对 anchor 取值做白名单校验。
环境
- 仓库:MoganLab/mogan @ d2242e3(2026-09-06)
- 平台:Linux x86_64(该函数在
LORO_ENABLED 下编译,影响所有开启协作的构建)
- 关联评估文档:
devel/1277.md(F3)
问题描述
协作(Loro CRDT)模式下,一个畸形/恶意远端光标载荷即可让本端在渲染路径上稳定 SIGSEGV,且
catch (string)挡不住段错误。edit_modify_rep::resolve_cursor(src/Edit/Modify/edit_collab.cpp,引入 commit 188dd26[0791] Collab: Structured Cursor)解析远端光标 off 字段时:off_field == "@O"(或"@C"等以@开头的 off 字段,例如对端发来peer:counter:@O)时at_pos == 0→core_off == "";string_rep::string_rep:a((n==0) ? ((char*)NULL) : ...)),string::operator[]无边界检查 → 空指针读 → SIGSEGV。触达路径(每帧重绘)
loro_collab.cpp:379→ed->set_remote_cursor (peer, payload)(载荷来自对端,仅按空格切 3 组、按冒号切字段,无语义校验);remote_cursors;edit_repaint.cpp:212→get_remote_cursors()对每个条目调resolve_cursor—— 每次重绘都会执行,一个坏条目让本端每一帧都崩,不是一次性崩溃。版本不匹配(如旧版客户端发
"@O"锚点格式)或畸形/恶意 peer 均可触发。复现(已验证)
--loro=y构建下,直接调用文件静态resolve_cursor的单测(SIGSEGV guard + 断言):实测输出(Debian 13,x86_64,d2242e3e5):
即
resolve_cursor(tid, "@O", ...)触发 SIGSEGV。等价的黑盒路径:set_remote_cursor("p1", "0:0:@O 0:0:@O 0:0:@O")后触发一次重绘。建议
resolve_cursor在char head= core_off[0];前补空串守卫(if (N (core_off) == 0) return path ();),与函数开头对off_field的守卫保持一致;同时对anchor取值做白名单校验。环境
LORO_ENABLED下编译,影响所有开启协作的构建)devel/1277.md(F3)