The CSRSS Backspace Bug in Windows NT 4/2000/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/2000/XP ?

This is the Frequently Given Answer for 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 affects all versions of Windows NT (Windows NT 4, Windows NT 2000, and Windows NT XP) irrespective of service pack. 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, although no-one has yet reported testing this.

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.)

    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 occurrs immediately after a TAB character, the console's cursor is erroneously moved backwards by more than one position. When this occurrs 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

As yet, Microsoft has issued no service pack that includes a fix for this bug.


© Copyright 2001-2001 Jonathan de Boyne Pollard. All Rights Reserved.
Permission is hereby granted to copy and to distribute this web page in its original, unmodified form, as long as no money is made from doing so.