Repository navigation
NVIDIA driver 2.3.7
NVIDIA driver 2.3.7
A security release. Everything 2.3.6 does, plus the fixes below. If you are on 2.3.6 this is a
straight upgrade: run install.sh and reboot once.
Security
This release closes a batch of defects found by auditing the driver against the bug classes Apple and
NVIDIA have published fixes for in their own graphics stacks. Several were reachable by any program on
the machine, and one was reachable from a web page.
- A video with a bad conformance window could write outside its buffer. The window is unbounded in
the bitstream, and a window wider than the picture made the visible width negative — a value then used
as a copy length. Both the H.264 and HEVC decoders now refuse a window that does not fit the picture.
These decoders run in every program that plays video, so the stream can arrive from a web page, a mail
attachment, or a preview. - The framebuffer published kernel addresses to any program. Every trace line it wrote went into a
registry property that needs no privilege to read, and the lines carried kernel code addresses, heap
addresses and GPU physical addresses — the pieces an attacker needs before anything else. The trace is
now off unless thenvfbtraceboot argument asks for it, and no log line prints an address. - GPU firmware moved to a directory only the installer can write. It was read from a shared folder
any user can write, with no check of what was in it. It now lives in/Library/NullMoth/nvfw, owned by
root with group and other write cleared, is checked against the digests the package shipped, and is
bounded in size. The installer refuses a firmware directory it did not create. - A client's teardown could run against its own in-flight call, freeing the list of memory ranges
while that list was being used to build a mapping. Each client now holds a lock across its calls and
its teardown, the teardown flag is set atomically, and the ranges are released when the client is
freed rather than when it closes. - A card mapping had to land inside one of this card's apertures, so a caller cannot hand over an
arbitrary physical address and have it mapped. - Texture and buffer regions are bounded by subtraction, not addition.
x + widthwrapped in 32 bits,
so a region starting near the top of the address space passed the bounds test and reached the GPU copy
as a negative offset; on the read side that returned memory from outside the texture. A region whose
64-bit fields do not fit the copy path is now refused outright instead of being narrowed into a
different region that looks valid. - Shader code is bounded before the compiler reads it, and a module the reader rejects is no longer
compiled anyway. Shader libraries are program-supplied data and can come from a game's content, a mod
or a download. - The kernel mapping table is serialised. Two mappings could take the same slot, and a release could
clear an entry while a lookup was reading it. - The installer checks and installs a private copy of the package. It verified the package and then copied
from the same folder minutes later, so anything that could write the extracted folder could swap a kernel
extension in between (PR #266, thanks Aniruddh Sahay). The accelerator extension was still read from the
original folder after that change; it now comes from the checked copy too. The package's own links are now
relative, so none of them points outside it. - A user-space door into the display engine is closed. Two driver calls let a root process open a display
session whose embedded pointers the display engine trusts as kernel addresses. Nothing the driver ships uses
them, so they now return "unsupported" (PR #267, thanks Aniruddh Sahay). - Smaller bounds, each reachable from an ordinary program: the plane index passed to a system lookup, the
firmware read length, the offset an argument encoder turns into a GPU address, a sysmem mapping length
that wrapped, and an address resolution that trusted identifiers from the caller instead of the
kernel's own record.
Fixes
- macOS 26 icons and Liquid Glass draw again. App icons were missing pieces — the App Store without its A,
Calendar without its header, Photos without its petals, Safari without its needle, System Settings without its
gears — and System Settings showed no icons at all. The system's icon and glass shaders call a linked visible
function behind a function constant. The driver decided whether such a function had to wait for its pipeline by
reading the shader compiler's error text, and when 2.3.6's compiler stopped refusing these outright its wording
changed, nothing matched, and the shader was dropped. The driver now asks the compiler for the function's
references instead. Checked against the same icons rendered on Apple silicon: 45 to 71 differing pixels of
65,536 on five of six, where 2.3.6 differed by 4,562 to 18,192. If your icons still look wrong after updating,
restart once more so the system redraws them. - Window dragging is smoother. A command buffer committed while the driver was waiting on an earlier one only
reached the GPU after that wait, so the compositor and the GPU took turns (PR #289, thanks watchthelight: 35 to
63 frames a second dragging a window on a 165 Hz panel). - The installer kept no copy of the GPU firmware when upgrading, because the firmware had moved and
the backup only looked in the new location. Both ways back — the uninstaller and the automatic fallback
that runs when a new driver cannot start — are gated on that copy, so on an upgrade they would have put
the previous driver back with no firmware at all, leaving a Mac with no display and no way out. The
backup now falls back to the old location. - The classic H.264 decoder is built from source like the other one. The two shipped libraries differ
only in the untiling layout the GPU writes; the classic one used to be produced by rewriting one
instruction in the finished library at a fixed offset, which meant a source fix could never reach it.
For people building on this
An external video encoder can now register beside ours instead of replacing it. Set NVMTL_NVENCVT in
/Library/GPUBundles/nvmtl/nvrm610.conf to 1, or to a list of program names, and the driver loads
libnvencvt.dylib from its own bundle directory. It is off by default, never loaded into the window
server, and refused unless both the library and the directory holding it are owned by root with group
and other write cleared. VideoToolbox picks between the encoders by rating, so both can be installed and
compared.
Donations
This work is free. Donations help keep it going: https://nullmothsystems.com/donate