Describe the bug
Update (edited): after filing I found the actual cause. Apple already fixed the MULX bug; OrbStack is loading an older Rosetta for Linux runtime than the one macOS ships, so amd64 guests still have it.
OrbStack 2.2.3 on macOS 26.6.2 maps Rosetta 367.4 into x86 processes (/mnt/rv/[rosetta]), while the host's /Library/Apple/usr/libexec/oah/RosettaLinux/rosetta is 367.9. Apple's container CLI (1.2.2) on the same Mac maps the host file (/run/rosetta/rosetta, identical hash) and the test below is correct there; under OrbStack it is wrong.
host file: /Library/Apple/usr/libexec/oah/RosettaLinux/rosetta -> 367.9, md5(first 64KiB) f3c478849d70e4e98244393a57361216
apple/container: /run/rosetta/rosetta (mapped in guest) -> md5(first 64KiB) f3c478849d70e4e98244393a57361216 (same as host)
OrbStack: /mnt/rv/[rosetta] (mapped in guest) -> 367.4, md5(first 64KiB) c5e224d10a7177399aff92ad31085375 (older build)
The hashes come from rosetta_fp.py (inline at the bottom), which reads the mapped Rosetta runtime out of /proc/self/mem and prints a hash of its first 64 KiB plus version-like strings. Rosetta AOT is not involved: freshly compiled binaries fail and ROSETTA_DISABLE_AOT=1 changes nothing.
Why it matters: Rosetta 367.4 still has Apple's MULX bug (rdar://171843590, diagnosed by Russ Cox in FiloSottile/age#633). MULX must leave flags untouched, but the old runtime clobbers the carry flag, so any carry-chain arithmetic after it is wrong. Since the guest CPUID advertises BMI2, anything doing runtime CPU detection (Go, Zig -mcpu=native, OpenSSL, ...) or built with -mbmi2 takes the broken path, and the failures look like application bugs.
Real-world impact I hit: a Zig program built inside the container fails every TLS handshake to hosts whose certificate chain has an ECDSA P-384 signer (x.ai, Google, GitHub, example.com) with CertificateSignatureInvalid, while RSA chains work. age users in the linked thread saw undecryptable files. It took a full day to trace back to the emulator.
To Reproduce
- Apple Silicon Mac, macOS 26.6.2, OrbStack 2.2.3.
- Start an amd64 container, install gcc, and run the attached
mulxcheck.c (sets CF with an overflowing ADD, executes MULX, reads CF back with ADC):
docker run --rm -it --platform linux/amd64 ubuntu:24.04 bash
apt-get update && apt-get install -y gcc
gcc -O0 -mbmi2 -o mulxcheck mulxcheck.c && ./mulxcheck
OrbStack output:
cpuid advertises BMI2: yes
carry flag after MULX: 0 -> WRONG (MULX clobbered CF)
Same binary, same Mac, under container run --arch amd64 ... (Apple container CLI 1.2.2):
cpuid advertises BMI2: yes
carry flag after MULX: 1 -> CORRECT
- Run
python3 rosetta_fp.py inside each guest to see which runtime is mapped (output above).
Guest environment: kernel 7.0.14-orbstack-00380-ga7e0a2dc9535, /proc/cpuinfo model VirtualApple @ 2.50GHz, flags include bmi1 bmi2.
Expected behavior
OrbStack should load the Rosetta runtime currently installed on the host, or refresh its copy whenever the host's changes (e.g. after a macOS update), so amd64 guests get Apple's fixes. With 367.9 the test prints carry flag after MULX: 1 -> CORRECT.
Diagnostic report (REQUIRED)
OrbStack info:
Version: 2.2.3
Commit: c83556b0ef8f1ba9a33abbb194622b6b7a1c0307 (v2.2.3)
System info:
macOS: 26.6.2 (25G83)
CPU: arm64, 12 cores
CPU model: Apple M4 Pro
Model: Mac16,8
Memory: 48 GiB
Full report: https://orbstack.dev/_admin/diag/orbstack-diagreport_2026-09-02T12-42-33.901573Z.zip
mulxcheck.c
Screenshots and additional context (optional)
rosetta_fp.py
import re, hashlib, os
maps = open("/proc/self/maps").read().splitlines()
mem = open("/proc/self/mem", "rb")
chunks = []
for line in maps:
if "rosetta" not in line.lower(): continue
parts = line.split()
start, end = (int(x, 16) for x in parts[0].split("-"))
perms, off = parts[1], int(parts[2], 16)
try:
mem.seek(start); data = mem.read(end - start)
except OSError as e:
print(f"{parts[0]} {perms} off={off:#x} unreadable: {e}"); continue
chunks.append((off, perms, data))
print(f"{parts[0]} {perms} off={off:#x} size={end-start:#x} {parts[5] if len(parts)>5 else ''}")
chunks.sort()
if chunks:
first = chunks[0][2]
print("ELF magic:", first[:4], "class/machine bytes:", first[4], first[18:20].hex())
print("md5 of first 64KiB at file offset", hex(chunks[0][0]), ":", hashlib.md5(first[:65536]).hexdigest())
blob = b"".join(c[2] for c in chunks)
print("total mapped bytes:", len(blob))
seen = set()
for m in re.finditer(rb"[\x20-\x7e]{6,120}", blob):
s = m.group().decode()
if re.search(r"(?i)rosetta|version|build|libexec/oah|advertise|AOT|cache", s) and s not in seen:
seen.add(s); print(" str:", s)
if len(seen) > 40: break
Describe the bug
Update (edited): after filing I found the actual cause. Apple already fixed the
MULXbug; OrbStack is loading an older Rosetta for Linux runtime than the one macOS ships, so amd64 guests still have it.OrbStack 2.2.3 on macOS 26.6.2 maps Rosetta 367.4 into x86 processes (
/mnt/rv/[rosetta]), while the host's/Library/Apple/usr/libexec/oah/RosettaLinux/rosettais 367.9. Apple'scontainerCLI (1.2.2) on the same Mac maps the host file (/run/rosetta/rosetta, identical hash) and the test below is correct there; under OrbStack it is wrong.The hashes come from
rosetta_fp.py(inline at the bottom), which reads the mapped Rosetta runtime out of/proc/self/memand prints a hash of its first 64 KiB plus version-like strings. Rosetta AOT is not involved: freshly compiled binaries fail andROSETTA_DISABLE_AOT=1changes nothing.Why it matters: Rosetta 367.4 still has Apple's
MULXbug (rdar://171843590, diagnosed by Russ Cox in FiloSottile/age#633).MULXmust leave flags untouched, but the old runtime clobbers the carry flag, so any carry-chain arithmetic after it is wrong. Since the guest CPUID advertises BMI2, anything doing runtime CPU detection (Go, Zig-mcpu=native, OpenSSL, ...) or built with-mbmi2takes the broken path, and the failures look like application bugs.Real-world impact I hit: a Zig program built inside the container fails every TLS handshake to hosts whose certificate chain has an ECDSA P-384 signer (x.ai, Google, GitHub, example.com) with
CertificateSignatureInvalid, while RSA chains work. age users in the linked thread saw undecryptable files. It took a full day to trace back to the emulator.To Reproduce
mulxcheck.c(sets CF with an overflowingADD, executesMULX, reads CF back withADC):OrbStack output:
Same binary, same Mac, under
container run --arch amd64 ...(Apple container CLI 1.2.2):python3 rosetta_fp.pyinside each guest to see which runtime is mapped (output above).Guest environment: kernel
7.0.14-orbstack-00380-ga7e0a2dc9535,/proc/cpuinfomodelVirtualApple @ 2.50GHz, flags includebmi1 bmi2.Expected behavior
OrbStack should load the Rosetta runtime currently installed on the host, or refresh its copy whenever the host's changes (e.g. after a macOS update), so amd64 guests get Apple's fixes. With 367.9 the test prints
carry flag after MULX: 1 -> CORRECT.Diagnostic report (REQUIRED)
OrbStack info:
Version: 2.2.3
Commit: c83556b0ef8f1ba9a33abbb194622b6b7a1c0307 (v2.2.3)
System info:
macOS: 26.6.2 (25G83)
CPU: arm64, 12 cores
CPU model: Apple M4 Pro
Model: Mac16,8
Memory: 48 GiB
Full report: https://orbstack.dev/_admin/diag/orbstack-diagreport_2026-09-02T12-42-33.901573Z.zip
mulxcheck.c
Screenshots and additional context (optional)
mulxcheck.c(standalone C test, needs only gcc).rosetta_fp.py(runtime fingerprint) is inline below.rosetta_fp.py