I the long distant past, the display driver dynamically generated code for a highly performance optimized BitBlt. It basically looked at the raster operation and pixel format, and generated code that was optimal for one scan line, and then ran this scan line code as many times as needed. Actually, on modern graphics systems, things like shaders I believe dynamically generate code, and if you’re running the software 3D renderer, that code may run on the main CPU instead of being loaded into the GPU.
There ARE some cases where dynamically generated code can significantly improve performance. A hypothetical example. Let’s say you have software RAID code, which needs to xor across 3 to 30 disk drives. It MIGHT be a useful performance optimization to dynamically generate (like at volume mount time) highly optimized code to do the xor on the correct number of drives, although you also could just burn memory and have a different function that was at compile time created for every combination of drives supported. This would trade no dynamic code generation for larger code, which with today’s memory sizes and security objectives, is perhaps a better tradeoff. In the past, the contract between the OS and driver developers has been you could dynamically generate code if needed, and this contract has been slowing changing, such that in Server 2016, dynamic code generation may no longer be allowed.
Unlike Linux, Windows has an expectation of BINARY driver compatibility in a new OS release. This compatibility is not always perfect, sometimes by design, and sometimes due to compatibility bugs. Linux on the other had has a stated policy of not even driver source compatibility between OS kernel releases. Drivers often work with no or minimal changes, but the Linux kernel team makes no major effort to maintain backward compatibility. This is a huge problem for companies that do not want to make public their driver sources. The Linux kernel team can basically declare no writable executable kernel memory, fixup some set of drivers in the kernel tree, and call it a done deal, without having to consider the impact on out of tree drivers. The Linux compatibility policy has the advantage of allowing the kernel to evolve faster, but has the disadvantage of causing third party driver developers arbitrary unscheduled work.
You should also keep in mind, THIS list is made of mostly third party driver developers, who have no control over what Microsoft puts in the kernel. There are some Microsoft folks here, who on occasion give third part developers useful insights, and perhaps take back some of what’s discussed here to discuss with the Windows kernel team. There is absolutely no expectation that anything discussed here will change decisions by the Microsoft kernel team.
It sounds like you, as a third part developer, would like to change some global behavior of the OS, making all executable kernel code read-only. You might technically find a way to do this, but the business question is: if you do this, is your company prepared to absorb the expense of possibility thousands of irate customer support calls, for the small percentage of systems this trick did not work on. Over the years, I’ve done my share of “bending the rules” to make something work, and the size of the risk you take needs to be offset by the size of the potential sales upside. Just by comparison, companies like Tesla would be taking a huge risk to sell a self-driving car, but that risk might be offset by the potential massive sales a self-driving car would have. Let’s say you wrote code that made all executable pages read-only, I’m not optimistic that would give you some unique product that had drastically better sales.
Hopefully this at least partially answers your question about why kernel pages aren’t all just executable and read-only.
Jan
From: on behalf of jc scaly
Reply-To: Windows List
Date: Monday, November 21, 2016 at 1:24 PM
To: Windows List
Subject: RE:[ntdev] Windows Kernel Writeable and Executable pages
I would very much like to leave the “are RWX pages a security flaw” talk out of this post and get back to understand: why are Windows kernel modules allocate and execute code dynamically.