GDR, QFE, LDR... WTH?

Update 2012-04-16:
Later related blog entries (as the topic grew in its scope and version numbering/branch identification changed after Windows Server 2003):

Branching Out (2009-05-18)
- gives a generic overview of the branching mechanism, with examples

Service Packs – Levels vs Installers (2009-05-29)
- distinguishes between “service pack level” and “service pack installer” for disambiguation

GDR & LDR : The Next Generation (2010-07-14)
- describes how to verify the version/branch of a given binary on XP/2003, Vista/W2K8 and Win7/W2K8R2

Original blog entry content follows:
Out of the box, all of the files in Windows are on what we refer to as the "General Distribution Release" (GDR) branch.

If updates are only delivered from Windows (or Microsoft) Update (including via WSUS), then all the files remain on the GDR branch.

Some KB articles have packages to address specific issues that are not delivered by Windows Update - "Limited Distribution Release" (LDR) branch packages.
Previously we used the term "Quick Fix Engineering" (QFE), but LDR has taken over – expect to see these terms used synonymously.

GDR packages contain only security and critical stability issue fixes.
LDR packages contain "other" fixes that have not undergone as extensive testing, and resolve issues that only a fraction of the millions of Windows users might ever encounter.

It is not the entire OS that is considered GDR or LDR - it is down to the individual file level.

A package delivered by Windows Update contains both GDR and LDR versions of the files it updates, so that it is able to replace the files on the system regardless of which branch they are currently on.

A package acquired outside of Windows Update contains only LDR versions of the files it updates, and this will "move" the files onto the LDR branch where they will remain until the next Service Pack.

A Service Pack (SP) contains only GDR branch versions of the files which have been updated by ANY package since the previous Service Pack (or RTM).

So installing the latest Service Pack at, or shortly after release will likely put all of your files (back) onto the GDR branch.

One other thing that Service Packs imply is that hotfix packages need to have versions of the files to replace for the most current SP level and the previous one (dubbed "N and N-1 support").

So for every single file updated by a Windows Update hotfix package after the first SP, there are 4 versions of the file present:
"N-1" GDR
"N-1" LDR
"N" GDR
"N" LDR

Taking a ficticious example, where we have the following files straight out of the box:
A.EXE RTMGDR 1.0
B.DLL RTMGDR 1.0
C.SYS RTMGDR 1.0

1) Hotfix package KB000001 is installed through windows Update, and contains an update to B.DLL - this pacakge contains:
B.DLL SP1GDR 1.1
B.DLL SP1LDR 1.1

> The SP1GDR version is installed by default, and there are only 2 (identical) versions of this file in the package as we're not yet at SP1.

The machine now has:

A.EXE RTMGDR 1.0
B.DLL SP1GDR 1.1 C.SYS RTMGDR 1.0

2) Hotfix package KB000002 is installed, NOT through Windows Update, and contains an update for A.EXE - this package contains:
A.EXE SP1LDR 1.02

> No options here, the version that ends up on disk is now the LDR version

The machine now has:

 A.EXE SP1LDR 1.02 B.DLL SP1GDR 1.1
C.SYS RTMGDR 1.0

3) Hotfix package KB000003 is installed through Windows Update and contains an update to A.EXE and C.SYS - this package contains:
A.EXE SP1GDR 1.11
A.EXE SP1LDR 1.11
C.SYS SP1GDR 1.11
C.SYS SP1LDR 1.11

> A.EXE is on the LDR branch because of KB000002, while C.SYS is still on the GDR branch

The machine now has:

A.EXE SP1LDR 1.11 B.DLL SP1GDR 1.1
C.SYS SP1GDR 1.11

4) Hotfix package KB000100 is installed through Windows Update, and contains an update for C.SYS for the RTM and SP1 versions of the OS - this package contains:
C.SYS SP1GDR 1.5
C.SYS SP1LDR 1.5
C.SYS SP2GDR 2.5
C.SYS SP2LDR 2.5

> OS level is still RTM, the current file is on the GDR branch, so we remain on the GDR branch

The machine now has:
A.EXE SP1LDR 1.11
B.DLL SP1GDR 1.1
C.SYS SP1GDR 1.5

5) SP1 is now installed on the system, which contains only GDR version 2.0 of every file:
A.EXE SP1GDR 2.0
B.DLL SP1GDR 2.0
C.SYS SP1GDR 2.0

> OS level is now raised to SP1 and we push all files on the GDR branch... but look what happens to C.SYS...

The machine now has:
A.EXE SP1GDR 2.0
B.DLL SP1GDR 2.0
C.SYS SP2GDR 2.5

> The SP1 package does not contain anything other then the GDR 2.0 versions of the files… so where did the GDR 2.5 version come from?

The hidden, compressed folders named $NtUninstallKBxxxxxx$ in the %systemroot% folder contain the backup of the version(s) of the replaced file(s) when the hotfix was applied, plus the executable to uninstall the package (in the spuninst sub-folder).

The hidden $hf_mig$ folder in the %systemroot% folder contains all the files extracted from the hotfix packages in sub-folders KBxxxxxx- these are necessary to ‘migrate’ the hotfix in the event that a switch of branches occurs or an earlier hotfix package is later installed.

 

In the example above at step 5, the post-SP1 hotfix package was used to migrate the updated version of C.SYS during the installation of SP1.
If this was not done, or if the folder had been deleted, then the file would have been regressed from 1.5 to 2.0.

What? A regression from a lower version to a higher version? Is that a typo?
Think of 1.5 as "RTM with KB000100" and 2.0 as "SP1 without KB000100" and it makes a bit more sense.

 

The migration of hotfixes to avoid regression is done from hotfix to hotfix as well as with SPs.

Imagine we have module X.DLL which has a dependency on module Y.DLL, and they both start at GDR 1.0.
Now a GDR hotfix KB000123 is applied which updates Y.DLL to 1.3.
Now an LDR hotfix KB000075 is applied which updates X.DLL to 1.1 and Y.DLL to 1.1.

The resultant files on the system would be:
X.DLL SP1LDR 1.1
Y.DLL SP1LDR 1.3

If we took Y.DLL 1.1 from the second hotfix then we regress in the security fixes, and if we left Y.DLL 1.3 from the GDR branch then we might miss a dependency that X.DLL LDR 1.1 may have which could lead to instability.

By switching to the LDR branch for the higher version of the file Y.DLL, we remain at the correct level in terms of security & stability fixes (changes in the GDR branch) but also add the fix for the issue mentioned in KB article KB000075.

Moving to the LDR branch for a specific KB article number will not just give you the security changes up to that point plus the 1 non-security issue mentioned in the KB article - it will also contain every non-security update to the files in the hotfix package.

For this reason you will see the all-too-familiar disclaimer:
"A supported hotfix is available from Microsoft. However, this hotfix is intended to correct only the problem that is described in this article. Apply this hotfix only to systems that are experiencing this specific problem. This hotfix might receive additional testing. Therefore, if you are not severely affected by this problem, we recommend that you wait for the next software update that contains this hotfix."

If you followed the above then you will also understand why you should never manually delete the $NtUninstallKBxxxxxx$ folders – you will be unable to remove these hotfix packages yet they will be listed in Add/Remove Programs (and you will gain very little disk space by doing this as the contents are compressed on disk).

If you were to delete the $hf_mig$ folder then you would break migration and may prevent the installation of future hotfixes or introduce unexpected regressions when installing service packs.

 

As if that wasn’t enough… you then have separate packages for the same hotfixes (where appropriate) x86 (i386/IA32), x64 (amd64) and IA64.

x86 is “only 32-bit” and IA64 is “only 64-bit”… but x64-based Windows has the concept of WOW (Windows-On-Windows) so these packages can have an even bigger list of files for the native 64-bit versions and the WOW6432 versions to support 32-bit apps.

Now you can see the value in the file lists documented in the KB articles, showing not just the file version number, but the different branches which have fixes, and this has de-mystified the versioning system a little.

 

The above is correct for Windows versions up to and including 5.2 (Server 2003 & XP x64 Edition) – when we moved to 6.0 (Vista) we changed how it works.