This page's shorter URL is http://tinyurl.com./ytllr.

The CSRSS Backspace Bug in Windows NT 4/NT 2000/NT XP.

You've come to this page because you've asked a question similar to the following:
What's the gen on the CSRSS backspace bug in Windows NT 4/NT 2000/NT XP ?

This is the Frequently Given Answer to that question.

Introduction

The CSRSS Backspace Bug is a bug in the Win32 subsystem server process (csrss.exe) in Windows NT. It is particularly notable for several reasons:

As far as I can determine, the first public report of the bug was on 2001-10-23, in a message posted by Masaru Tsuchiyama in the comp.os.ms-windows.programmer.win32 newsgroup on Usenet, who attributes its discovery to "a co-worker".

Systems affected

The bug definitely affects all versions of Windows NT from version 4 onwards (Windows NT 4, Windows NT 2000, and Windows NT XP) irrespective of service pack, except for Windows NT 2000 with service pack 3 applied and Windows NT XP with service pack 1 applied.

Because csrss.exe has been a part of Windows NT from the beginning, it probably affects Windows NT 3.5 and Windows NT 3.1 as well. (I have seen a report that appears to confirm that this bug does indeed affect Windows NT 3.5 and Windows NT 3.1. However, this report was originally written in German, and may have been incorrectly translated.)

No version of DOS-Windows (DOS-Windows 3.x, DOS-Windows 95, DOS-Windows 98, or DOS-Windows ME) is affected by this bug. DOS-Windows does not have a csrss.exe process.

Severity

This bug causes an access violation in the csrss.exe process. Normally, with other processes, an access violation causes a message box to be displayed containing a dump of the state of the process, and the process to be terminated. If a debugger is installed, one is given the option to debug the process. The Windows NT operating system carries on unaffected, and other processes continue to run.

However, Windows NT considers csrss.exe to be a vital system process, just like Unix considers process 1, init, to be a vital system process. If process 1 dies for whatever reason on Unix, the kernel issues a "panic" message. If csrss.exe dies for whatever reason, Windows NT considers the error to be unrecoverable and halts with a "bug check" (i.e. the infamous "Blue Screen of Death"). (Windows NT considers winlogon.exe to be similarly vital, and will halt with a "bug check" if that process ever dies for any reason too.)

No application program data will be saved. Files and directories whose contents are not in the process of being altered at the time of the crash are very unlikely to be affected, however.

Aside: csrss.exe owes its very existence to a notion, taken from microkernel operating systems, that system services run as ordinary application processes, rather than as part of the kernel. The very intention of this design is that if a system process dies, it does not take the kernel with it. Unfortunately, Windows NT committing suicide in sympathy when it notices that csrss.exe has died defeats this entire idea. (Windows NT is not a microkernel operating system, of course.)

How to replicate the bug

This bug is triggered by writing ordinary text characters to a console. Here is the simplest means for doing so:

  1. Obtain or create a text file that contains an arbitrary sequence of printable characters followed by a TAB (ASCII code 9) character and a repeated sequence of BACKSPACE (ASCII code 8) characters. One can use any text editor to create the file, provided that it allows one to enter backspace characters in text files. (notepad does not. However, edit does. Simply press [Ctrl-P] before pressing the [TAB] and [Backspace] keys.)

    A simple QBASIC program to create such a text file is:

    OPEN "CSRSSBUG.TXT" FOR OUTPUT AS 1
    FOR I% = 1 TO 4096
        PRINT #1, I%; CHR$(9); STRING$(16, 8);
    NEXT
    
  2. Display this text file on a console using the TYPE command.
    TYPE CSRSSBUG.TXT

One can also write a short (around 10 lines) C or C++ language program to trigger the bug. This bug involves the actual handling of backspace characters when written to consoles using high-level console I/O. The exact mechanism by which the text characters reach the console is immaterial. Programs that call WriteConsole or WriteFile, or any C library routines that are layered on top of them such as fputs or printf, will all cause the bug to trigger.

This is true even of non-Win32 Windows NT programs that perform high-level console I/O, such as POSIX Windows NT programs. Displaying the file using the POSIX cat command supplied by Microsoft will trigger this bug, for example.

One can also write a short script to trigger this bug in any scripting language that allows one to write characters to standard output, including VBScript, perl, and REXX. Here is a 3 line REXX script, for example:

do forever
    call charout ,"090908080808080808080808080808080808"X
end

When the bug will not be replicated

This bug will not be triggered by programs that display data using low-level console I/O. Displaying a text file containing backspace characters using a list command that presents a scrollable "full-screen" interface, for example, will not trigger this bug.

This bug is not triggered by the cat command supplied by Cygwin. (Ironically, given that Cygwin is largely used to compile programs that use the POSIX system API, Cygwin programs are actually Win32 programs, not POSIX Windows NT programs. Cygwin interposes its own processing on top of the Win32 high-level console I/O processing which by chance happens to avoid this bug.)

This bug cannot be triggered by a QBASIC program. The PRINT statement in QBASIC actually performs low-level console I/O internally.

Security

No access controls influence the triggering of this bug, and no user privileges are required in order to trigger it.

Distributed and remote exploits

What is actually going wrong

This bug is a combination of

The design flaw in Windows NT is that, as has already been described, Windows NT commits suicide in response to the death of the csrss.exe process. The bounds-checking error in the handling of high-level console I/O is described here.

In Windows NT, csrss.exe handles all I/O to and from consoles. When a character is displayed using high-level console I/O it is csrss.exe that performs the nitty-gritty of actually modifying the console screen buffer (if the character is printable) and moving the cursor position.

The code in csrss.exe does not correctly handle the occurrence of backspace characters at the beginning of lines. (If one invokes the debug kernel of Windows NT XP, and writes a series of backspace characters to the console, one sees debug messages being issued by "CONSRV" claiming that it is ignoring attempts to backspace over the beginning of a line. Nonetheless, the cursor does move from the beginning of a line to the end of the previous line in response to a backspace character. It is unknown whether the behaviour is intended and the message is erroneous, or the behaviour is erroneous and the message is describing what the behaviour was intended to be.)

Most importantly, the code in csrss.exe does not correctly handle the occurrence, in a single high-level console I/O write operation, of a backspace character occurring immediately after a TAB character near the beginning of the first line in the console screen buffer. When, in a single high-level console I/O write operation, a backspace character occurs immediately after a TAB character, the console's cursor is erroneously moved backwards by more than one position. When this occurs at the beginning of a line, the console's cursor is moved onto the previous line. When this occurs on the first line, the console's cursor will be erroneously moved to point to a position outside of the console screen buffer. If, next, a printable character is sent to the console for display, the console buffer modification code in csrss.exe will write to a memory address in the csrss.exe process that is outside of the memory allocated for the console screen buffer.

The exact consequences of this write depend from the exact pattern of heap usage in the csrss.exe process, and whether or not the memory immediately preceding the memory used to hold the console screen buffer cell array is committed and in use. This in turn depends from what and how many consoles have been opened, and what other tasks csrss.exe has performed. This is one of the reasons that some programs to trigger this bug do not cause it to trigger in all cases. The text file generated by the QBASIC program given above repeats the trigger sequence 4096 times, to increase the probability that the bug will be triggered irrespective of starting cursor position and memory usage patterns in the csrss.exe process. However, in many cases it is only necessary to write the trigger sequence to the console once and let the access violation be caused by the next printable character being displayed (such as when the command interpreter displays its prompt).

Local fix

There is no known local fix for this bug. Given the analysis, it does not appear likely that a local fix is possible.

Temporary fix

As yet, Microsoft has issued no hotfix for this bug.

Service fix

There will not be further service packs for Windows NT 4. This is a permanent bug in Windows NT 4.

On 2002-03-23, almost five months since this bug became public knowledge and this web page was published, I received an unconfirmed report from a third party that a fixpack that includes a fix for this bug will be released, and that a knowledgebase article covering it "will" be written.

On 2002-08-01, nine and a half months since this bug became public knowledge and this web page was published, Microsoft released the third service pack for Windows NT 2000. With this service pack applied, it appears to be impossible to reproduce this bug. However, neither the change that causes this nor even the bug itself are listed anywhere in either the Windows NT 2000 service pack documentation or in Microsoft's KnowledgeBase. The problem does not officially exist, and is certainly not officially solved. The worry here is that the fact that it is no longer reproducable is coincidental, and (since Microsoft has not recognised it to actually be a problem, and therefore will not include it in any regression testing) liable to be reintroduced by subsequent service packs.

On 2002-09-09, ten and a half months since this bug became public knowledge and this web page was published, Microsoft released the first service pack for Windows NT XP. As with the Windows NT 2000 service pack, there is no official acknowledgement in the service pack documentation either that the bug exists or that it has intentionally been fixed by the service pack. I was unable myself to confirm that the bug is indeed fixed by the service pack, and no-one else had yet reported to me that it is.

On 2002-09-12, the same third party that reported the fixpack information to me reported Microsoft as saying to him that it has

a KB article that should be live soon
and that this will, when it appears, be Microsoft KnowledgeBase article ID Q311486. I confirmed that no article by that ID was currently available.

On 2002-09-24, Microsoft KnowledgeBase article ID Q311486, promised six months ago, finally appeared. Its publication date is falsified to claim that it appeared on 2001-10-26. It talks about programs that "pass invalid screen size parameters" when the sample program code that it gives for replicating the bug clearly contains nothing at all relating to screen size parameters. And the explanation that it gives for the actual cause of the problem is woefully incorrect. Were it not that it has taken over eleven months for Microsoft to produce it, one might think that this article was a very badly done rush job.

On 2002-10-29, another third party, who had access to a Windows NT XP system with the first service pack applied, reported to me confirming that on that system it was now impossible to reproduce this bug.


© Copyright 2001–2002 Jonathan de Boyne Pollard. "Moral" rights asserted.
Permission is hereby granted to copy and to distribute this web page in its original, unmodified form as long as its last modification datestamp is preserved.