Fix macOS 26 (Tahoe) support and harden XPC, config parsing, and logging - #985
Open
godlockin wants to merge 87 commits into
Open
Fix macOS 26 (Tahoe) support and harden XPC, config parsing, and logging#985godlockin wants to merge 87 commits into
godlockin wants to merge 87 commits into
Conversation
Misc additional changes and cleanup
`RunLoopLocalEventMonitor` seems to prevent certain buttons from receiving events in macOS 26 Developer Beta 1. This might be a bug in the beta, or `RunLoopLocalEventMonitor` itself. For now, let's just move to a better mouse check implementation that doesn't use continuous event monitoring. Note the `FIXME` (line 1057). The previous implementation had this problem too, but it was never documented.
A big part of this is hopefully a temporary measure. We need an accurate identifier for every item, and the old way just isn't cutting it right now. Items are all owned by the Control Center in macOS 26, and try as I might, I couldn't find a great way to get the _actual_ host apps for the items. Must dig deeper into the mines... Oh yeah, there's also a bunch of random stuff here too that I don't really want to explain. Just know that it probably all fixed something.
This is what I get for trusting Xcode to update my build settings
- Refactor screen capture - Rework menu bar item getters - Update immovable/non-hideable info lists - Remove OSLog wrapper - Minor migration rework - Remove old entitlements file
Should also fix a crash when accessing `ControlItem.windowNumber`.
- Rework app lifecycle - Rework how windows are initialized - Update documentation comments - Refactoring and cleanup
This should fix some performance issues that occur during mouse tracking operations (e.g. highlighting a button on hover).
We also store the status item and layout constraint in a separate storage class. Not sure I like this, but the idea is to convey the tightly coupled relationship between the constraint and status item, and to ensure that they are initialized (and deinitialized) at the same time.
Relying on the default behavior seemed to work fine, but is now broken in the macOS 26 Developer Beta. Probably better to handle it explicitly, even if it is just a beta bug.
- Documentation changes
- Misc event handling improvements - Fix temporarily shown item interface check - Fix broken on screen item check - Additional minor refactoring
Revert to using a direct call to the `CGImage` initializer, rather than calling it through a static protocol method (this was originally done to suppress the deprecation warning, but it seems to cause screen capture to fail for some users).
…ing its monitors
…fier Ad-hoc signed builds (e.g. local builds without a signing certificate) have no team identifier, so the isFromSameTeam() requirements enforced by both the MenuBarItemService listener and the app-side connection reject every connection, breaking menu bar item retrieval on macOS 26. Only enforce the requirement when our own signature has a team.
Sparkle 2.8.0 (previously resolved) is affected by CVE-2026-47121 (path traversal) and CVE-2026-47122 (unvalidated post-stage-1 XPC listener accepting spoofed appcast data), both fixed in 2.9.2.
Stored key combinations are untrusted input, since any process in the user session can write to the app's defaults domain: - Reject out-of-range key codes and modifiers at decode time. A negative key code previously reached UInt32() and trapped on every launch, permanently crashing the app until the defaults were cleared. - Convert to UInt32 with UInt32(exactly:) at registration time as a second line of defense. - Skip combinations that are reserved for system use, so a hostile defaults write can't register system shortcuts (e.g. Command-Tab) as Ice hotkeys.
CGColor reads colorSpace.numberOfComponents values from the components buffer, so a stored configuration with fewer components than the color space requires would read out of bounds. Reject it at decode time instead.
Security audit follow-ups for the ad-hoc (no team) build path and the service side: - CodeSigningInfo now distinguishes a verifiably team-less signature from a failure to read signature information. Peer verification is skipped only in the former case; read failures keep verification enabled (fail closed). The decision is logged on both sides. - The source PID request now carries only the window ID and bounds the service needs, instead of the full WindowInfo, shrinking the decode surface on the service side. - The service remembers failed lookups for 5 seconds and rate limits scans of unknown windows to 10/sec, so a client flooding the service with random window IDs can no longer pin it in full accessibility scans. The failed-lookup map is pruned when it grows too large. - The listener retries activation instead of silently leaving the service dead if the mach name is momentarily taken. - The app validates that a returned PID belongs to a running application before using it, discarding forged or stale responses. - The app keeps a strong reference to the activated session in shared storage; releasing an active XPCSession traps in _xpc_api_misuse, which crashed the app shortly after startup.
- Item and error descriptions (which embed window titles read via kCGWindowName) are no longer logged with privacy: .public, so they are redacted in the unified log instead of being readable by any process in the session. - Event barrier continuations are now resumed through a once-only guard, since the tap callback and the cancellation handler can race to resume the same continuation, which traps.
- Evict cached item images whose items no longer exist, so captures of hidden or removed items don't stay in memory indefinitely. - Redact application identifiers from spacing manager logs. - The search panel now monitors key down events locally instead of globally; the panel is key while shown, so a global monitor observed keystrokes destined for other applications for no benefit. - Remove the unused RunLoopLocalEventMonitor, whose pattern of draining and replaying the app event queue is dangerous if ever reused.
- Require Sparkle 2.9.2+ and pin the downloaded asset archive by SHA-256, so a replaced upstream archive fails the build instead of being silently bundled. - Sign the assembled app and XPC service with the hardened runtime, matching what xcodebuild produces.
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.
Summary
This PR brings the work from the
macos-26branch intomainso Ice works on macOS 26 (Tahoe), and adds security hardening identified in a full audit of the merged result. Verified end-to-end on Apple Silicon (M4 Pro, macOS 26.6.2): menu bar item hiding/showing, theMenuBarItemServiceXPC service, and rehide timers all work.1. macOS 26 (Tahoe) support
macos-26branch (0.11.13-dev.2a) intomain, picking up the menu bar item retrieval/event handling reworks that Tahoe requires.2. Security hardening
UInt32()and trapped on every launch, a persistent crash-loop DoS that survived reinstall. They are now rejected at decode time, withUInt32(exactly:)as a second line of defense at registration.IceColornow validates that the decoded components array has at leastcolorSpace.numberOfComponentsentries before constructing aCGColor(previously a heap out-of-bounds read).MenuBarItemServiceXPC channel (macOS 26 path):CodeSigningInfodistinguishes a verifiably team-less signature (ad-hoc builds, where same-team peer requirements can never be satisfied) from a failure to read signature information. Verification now fails closed on read failures, and the decision is logged on both sides.WindowInfo, shrinking the decode surface.XPCSessiontraps in_xpc_api_misuse.kCGWindowName) is no longer logged withprivacy: .publicat persisted levels, closing a side channel readable by any process in the session.RunLoopLocalEventMonitor(drains and replays the app event queue) was removed; event barrier continuations are guarded against double resume.3. Building without full Xcode
Scripts/build-without-xcode.shbuilds Ice.app using only the Command Line Tools via SwiftPM: stages the sources, strips#Previewblocks (whose macro plugin ships only with Xcode), reuses the compiled asset catalog from the official release archive pinned by SHA-256, then assembles and ad-hoc signs the bundle with the hardened runtime. Handy for contributor machines without a full Xcode install.Fixes #709