Skip to content

LATX, fix: Separate KZT host pointers from guest virtual addresses - #397

Merged
LaurenIsACoder merged 1 commit into
lat-opensource:masterfrom
LaurenIsACoder:lauren/kzt-wine-address-tradeoff
Aug 15, 2026
Merged

LATX, fix: Separate KZT host pointers from guest virtual addresses#397
LaurenIsACoder merged 1 commit into
lat-opensource:masterfrom
LaurenIsACoder:lauren/kzt-wine-address-tradeoff

Conversation

@LaurenIsACoder

@LaurenIsACoder LaurenIsACoder commented Aug 13, 2026

Copy link
Copy Markdown
Contributor

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_va as 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 0x7ffffffb0000 could bypass the guest range checks and reach target_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:

  • Guest memory operations such as mmap(), mprotect(), munmap(), mremap(), and shmat() must remain inside the guest virtual-address window.
  • Existing KZT wrappers retain a dedicated compatibility path for host-owned data outside the guest window.
  • KZT executable entries are accepted only when they match a registered onebridge slot or an existing X11 TB bridge entry.
  • Zero-length, overflowing, and guest/host-boundary-crossing ranges are rejected.
  • Bridge publication and lookup are synchronized so that partially initialized slots are not visible.

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 虚拟地址范围内;
  • 现有 KZT wrapper 继续通过专用兼容路径访问 guest 范围之外的宿主数据;
  • 可执行 KZT 入口必须准确命中已登记的 onebridge slot 或已有的 X11 TB bridge;
  • 拒绝零长度、整数溢出以及跨越 guest 地址上限的范围;
  • bridge 的发布和查询进行同步,避免看到未完成初始化的 slot。

长期完整方案应当登记每一个需要暴露给 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:

  • Full latx-x86_64 build: PASS
  • test-kzt-address-policy: PASS
  • All 51 available library probes were compared with LATX_KZT=0/1: 50 passed in both modes; the libXt probe crashed identically in both modes, so this patch introduced zero new KZT-only failures
  • GitHub checks: 20/20 PASS (15 build configurations, 4 LAT test jobs, and DCO)
  • Wine 11.14 wine --version:
    • LATX_KZT=0: PASS
    • LATX_KZT=1: PASS
  • Wine 11.14 wineboot -u:
    • LATX_KZT=0: exited successfully
    • LATX_KZT=1: the original target_mmap() segmentation fault was not reproduced during a 60-second run; libc, X11, GLX, GL, and EGL wrapper initialization continued before the timeout

The 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:PASS
  • test-kzt-address-policy:PASS
  • 对全部 51 个现有库探针进行了 LATX_KZT=0/1 对照:50 项在两种模式下均通过;libXt 探针在两种模式下均同样崩溃,因此本补丁新增的 KZT 独有失败为 0
  • GitHub 检查:20/20 PASS(15 个构建配置、4 个 LAT 测试任务以及 DCO)
  • Wine 11.14 wine --version
    • LATX_KZT=0:PASS
    • LATX_KZT=1:PASS
  • Wine 11.14 wineboot -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 回归测试。

@LaurenIsACoder
LaurenIsACoder force-pushed the lauren/kzt-wine-address-tradeoff branch from c82cdfc to 8cad21b Compare August 13, 2026 13:31
@LaurenIsACoder
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
LaurenIsACoder force-pushed the lauren/kzt-wine-address-tradeoff branch from 8cad21b to 92ac78d Compare August 15, 2026 01:48
@LaurenIsACoder
LaurenIsACoder merged commit 0677a6f into lat-opensource:master Aug 15, 2026
20 checks passed
@LaurenIsACoder
LaurenIsACoder deleted the lauren/kzt-wine-address-tradeoff branch August 15, 2026 01:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant