LATX, fix: Separate KZT host pointers from guest virtual addresses - #397
Merged
LaurenIsACoder merged 1 commit intoAug 15, 2026
Conversation
LaurenIsACoder
force-pushed
the
lauren/kzt-wine-address-tradeoff
branch
from
August 13, 2026 13:31
c82cdfc to
8cad21b
Compare
LaurenIsACoder
marked this pull request as ready for review
August 15, 2026 01:44
KZT previously treated every address as a valid guest address so native wrapper pointers and bridge entry points could be accessed. That also let Wine mapping probes escape the reserved guest virtual-address window and reach host mmap addresses. Keep guest mapping validation strict, while retaining a separate compatibility path for host-owned wrapper data. Register bridge slots and classify executable KZT entries by exact membership instead of their numeric address, including the X11 TB bridge table. Snapshot bridge metadata while holding the registry lock so translation and logging cannot race with bridge teardown. Add unit coverage for guest bounds, host pointers, zero lengths, crossing ranges, and overflow. Signed-off-by: Hanlu Li <heuleehanlu@gmail.com>
LaurenIsACoder
force-pushed
the
lauren/kzt-wine-address-tradeoff
branch
from
August 15, 2026 01:48
8cad21b to
92ac78d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Background / 背景
KZT replaces selected guest library functions with native host functions. Some wrappers therefore expose host-owned data pointers or native bridge entry points to translated guest code.
These addresses are valid for KZT, but they are not ordinary guest virtual addresses managed by the linux-user page map.
To keep these paths working, the previous implementation accepted every address and range while KZT was enabled, and treated addresses above
reserved_vaas possible native bridges. This was a compatibility workaround: without it, existing wrapper data and bridge addresses could be rejected by normal guest-address checks.KZT 会将部分 guest 动态库函数替换为宿主原生函数,因此一些 wrapper 会向翻译后的 guest 代码暴露宿主数据指针或原生 bridge 地址。
这些地址对 KZT 是合法的,但不是由 linux-user 页表管理的普通 guest 虚拟地址。
旧实现为了保持这些路径可用,在开启 KZT 后接受所有地址和地址范围,并把高于
reserved_va的地址视为可能的原生 bridge。这是一项兼容措施,否则现有 wrapper 使用的宿主数据和 bridge 地址可能被普通 guest 地址检查拒绝。Problem / 问题
The compatibility workaround also made arbitrary high guest addresses appear valid.
Wine probes and reserves large parts of the x86-64 virtual-address space during startup. An address outside LATX's reserved guest window should be rejected so that Wine can try another range.
With KZT enabled, a Wine request around
0x7ffffffb0000could bypass the guest range checks and reachtarget_mmap()as if it were a valid guest mapping. A fixed host mapping outside the reserved guest window may conflict with LATX's own mappings and cause a host-side segmentation fault.The problem is not Wine's probing behavior. The problem is that KZT used the same permissive rule for guest mappings, host data pointers, and executable bridges.
旧的兼容措施也使任意 guest 高地址看起来都是合法的。
Wine 启动时会探测并预留较大的 x86-64 虚拟地址空间。超出 LATX guest 预留范围的请求应当被拒绝,让 Wine 继续尝试其他地址。
开启 KZT 后,Wine 在
0x7ffffffb0000附近的请求可能绕过 guest 地址检查,以普通 guest 映射的形式进入target_mmap()。在 guest 预留范围之外执行固定地址的宿主映射,可能与 LATX 自己的映射冲突并导致宿主侧段错误。问题不是 Wine 的探测行为,而是 KZT 使用同一个宽松规则处理了 guest 映射、宿主数据指针和可执行 bridge 三种不同地址。
Change and tradeoff / 修改与权衡
This change separates the three address uses:
mmap(),mprotect(),munmap(),mremap(), andshmat()must remain inside the guest virtual-address window.The complete long-term solution would register every guest-visible host object with its size, type, owner, and lifetime. That requires auditing and migrating all wrappers, callbacks, data symbols, and
dlopen()/dlclose()paths.This patch therefore uses an incremental tradeoff: guest mappings and executable bridges are checked strictly now, while the existing host-data compatibility path is retained to avoid breaking current wrappers.
本次修改将三种地址用途分开处理:
mmap()、mprotect()、munmap()、mremap()和shmat()等 guest 内存操作必须位于 guest 虚拟地址范围内;长期完整方案应当登记每一个需要暴露给 guest 的宿主对象,并记录其大小、类型、所有者和生命周期。但这需要同时审计和迁移所有 wrapper、callback、数据符号以及
dlopen()、dlclose()路径。因此,本补丁采用渐进式权衡:现在先严格限制 guest 映射并准确识别可执行 bridge,同时保留现有宿主数据兼容路径,避免破坏已有 wrapper。
Known limitations / 已知限制
Host-data compatibility still does not prove that every accepted high data pointer was created by a KZT wrapper.
Host-object ownership and
dlopen()/dlclose()lifetime are not yet tracked.This patch safely rejects Wine's out-of-range probes, but does not eliminate Wine's repeated address probing after
ENOMEM.Exact bridge classification adds a small synchronized lookup when LATX classifies or translates a possible bridge entry. It is not added to every execution of an already translated wrapper call.
Wrapper ABI, callback conversion, and allocator ownership remain separate correctness requirements.
宿主数据兼容路径仍不能证明每一个被接受的高地址都由 KZT wrapper 创建;
尚未管理宿主对象的所有权以及
dlopen()、dlclose()生命周期;本补丁可以安全拒绝 Wine 的越界探测,但没有消除 Wine 收到
ENOMEM后继续尝试其他地址的开销;LATX 判断或翻译可能的 bridge 入口时会增加一次同步查询,但不会增加到每次已经完成翻译的 wrapper 调用中;
Wrapper ABI、回调转换和内存分配所有权仍然需要独立保证。
Validation / 验证
Tested on AOSC LoongArch64 with a 16 KiB host page size:
latx-x86_64build: PASStest-kzt-address-policy: PASSLATX_KZT=0/1: 50 passed in both modes; the libXt probe crashed identically in both modes, so this patch introduced zero new KZT-only failureswine --version:LATX_KZT=0: PASSLATX_KZT=1: PASSwineboot -u:LATX_KZT=0: exited successfullyLATX_KZT=1: the originaltarget_mmap()segmentation fault was not reproduced during a 60-second run; libc, X11, GLX, GL, and EGL wrapper initialization continued before the timeoutThe initial Wine process and the LATX executable used after Wine re-exec were verified to have the same SHA-256.
A temporary audit build recorded 72 entries into registered onebridge translation during KZT-enabled Wine startup. The audit logging was removed before the production build and is not included in this PR.
在采用 16 KiB host page 的 AOSC LoongArch64 系统上测试:
latx-x86_64:PASStest-kzt-address-policy:PASSLATX_KZT=0/1对照:50 项在两种模式下均通过;libXt 探针在两种模式下均同样崩溃,因此本补丁新增的 KZT 独有失败为 0wine --version:LATX_KZT=0:PASSLATX_KZT=1:PASSwineboot -u:LATX_KZT=0:正常退出LATX_KZT=1:60 秒内未再复现原来的target_mmap()段错误;超时前继续完成了 libc、X11、GLX、GL 和 EGL wrapper 初始化测试前已经确认 Wine 首进程和重新执行后使用的 LATX 文件具有相同的 SHA-256。
临时审计构建在开启 KZT 的 Wine 启动过程中记录到 72 次进入已登记 onebridge 的翻译路径。审计日志已经在生产构建前删除,不包含在本 PR 中。
The timed KZT-enabled Wine run is not presented as a complete Wine startup pass. Complete KZT regression testing is still required before marking the PR ready.
当前 KZT Wine 测试由 timeout 停止,不能作为 Wine 已完整启动成功的证明。在将 PR 标记为 Ready 前,仍需完成完整 KZT 回归测试。