In Windows NT 3.5x most of the graphic interface was handled in user mode, causing a lot of slow user/kernel/user mode changes. To improve speed, in NT 4.0, most of the GUI code was moved into kernel mode, but they forgot to add the parameter cheks :-). Just calling some innocent looking GUI routine and passing a null pointer by mistake, where a valid pointer was required could cause the BSOD :-).
NT4.0 SP1 at least added parameter checks.
The situation with NT4 service packs was as bad as with the base operating system version, only every other service pack was usable, since it patched the bugs introduced by the previous SP :-).
Regarding the kernel mode overwriting problems, part of the blame goes to Intel, since the 386+ family only contained write protection on the segment register level, but not on virtual memory page level. Super minicomputers in the 1970's had page level write protection, so this was nothing new when the 386 was created.
If the OS had used sensible code and data virtual address mapping, even the limited segment based protection would have helped a lot to catch bugs.
While handling exceptions caused by kernel mode access is risky in a production system, at least a lot of kernel driver bugs could have been detected during during driver testing, if the driver address space could be limited.
Fortunately, the most recent versions of the x86 architecture will provide some page level protection against illegal memory access.