Other

  • The Old New Thing

    2015 mid-year link clearance

    • 11 Comments

    The semi-annual link clearance is here!

  • The Old New Thing

    Windows 95 and Windows NT manage the TEB on x86 differently

    • 22 Comments

    Today, a historical note of no consequence. Just a story.

    The Win32 x86 ABI specifies that the FS register holds a selector which is based at the current thread's TEB. In other words, fs:[n] is the nth byte of the TEB.

    It so happens that the two operating systems chose to manage the FS register differently.

    Windows 95 gave each TEB in the system its own selector.

    Windows NT allocated a single selector to represent the TEB, and each time the processor changed threads, the selector base was updated to match the TEB for the new thread. With this model, every thread has the same value for FS, but the selector's descriptor kept changing.

    It's as if you had a car-rental service, and one of the features of the service is that the radio remembers your presets. The instructions for setting the radio are as follows:

    • Enter the four-digit customer preferences ID printed on your receipt.
    • Your radio is now set to your preferences.

    There are two ways you could set up this system.

    Windows 95 assigns each customer a unique customer preferences ID and prints it on the receipt. When the customer enters the ID, the radio looks up the ID in a database and applies the user's radio preferences.

    Windows NT prints the same preferences ID on every receipt: 1234. Before the customer picks up the car from the rental service, the service agent sets the radio to the customer's preferences. When the customer enters the ID, the radio does nothing (aside from printing an error message if you enter anything other than 1234).

    Even though the Windows NT way creates more work for the service agent, it does solve an important problem: It lets your service scale to more than 10,000 customers, for once you have 10,001 customers, you cannot assign each of them a unique four-digit ID any more.

    Car Windows
    car processor
    customer thread
    radio preferences TEB
    customer ID selector

    By assigning a unique selector to each TEB, Windows 95 limited itself to at most 8192 threads. (In practice, the limit was much lower because selectors were used for other things, too.) This was not an issue in practice because Windows 95 would run into other problems long before you ran into the 8192-thread limit.

    But Windows NT was designed to be scalable to very large workloads, and they couldn't artificially limit themselves to a maximum of 8192 threads.

    The consequences of changing the meaning of the FS register at every thread switch means that some tricks that happened to work in Windows 95 didn't work in Windows NT. For example, in Windows 95, if you captured the value of the FS register in one thread, you could use it (in violation of the ABI) on another thread in the same process and still access the originating thread's TEB. If you tried this trick on Windows NT, you would just see your own TEB.

    In the analogy, it's as if you copied the customer preferences ID from another customer's receipt and tried to use it in your car. In a Windows NT car, you would just get your own preferences again, because every receipt has the same customer preferences ID printed on it.

    According to the Win32 ABI for x86, the only thing you can do with the FS register is dereference it to access your TEB. If you try to fiddle with its value or try to copy its value somewhere, you are off in unsupported territory, and the resulting behavior is undefined.

  • The Old New Thing

    One way to make sure nobody reports problems with your Web site

    • 16 Comments

    I had ordered a service online, and the Web site said, "Do not close this window until you are done, because once you close the window, you won't be able to come back."

    Okay, fine. I just need to make sure I get everything I need before I close the window.

    I click a link to download some of the information I had ordered, and I get the error message:

    We're having trouble processing your request.
    If this problem persists please let us know.
    Email us at null

    Related.

  • The Old New Thing

    Under what conditions can SetFocus crash? Another debugging investigation

    • 10 Comments

    A customer asked, "Under what conditions can Set­Focus crash?"

    We have been going through our error reports and are puzzled by this one. The call stack is as follows:

    user32!_except_handler4
    ntdll!ExecuteHandler2@20
    ntdll!ExecuteHandler@20
    ntdll!RtlDispatchException
    ntdll!_KiUserExceptionDispatcher@8
    0x130862
    user32!UserCallWinProcCheckWow
    user32!__fnDWORD
    ntdll!_KiUserCallbackDispatcher@12
    user32!NtUserSetFocus
    contoso!DismissPopup
    

    At the point of the crash, the Dismiss­Popup function is calling Set­Focus to restore focus to a window handle that we got from an earlier call to Get­Active­Window. Is this safe? We imagine it might crash if the message handler for the window was unloaded from memory without being properly unregistered; are there any other reasons? More to the point, is there any way to avoid the problem (without fixing the root cause of the crash, which we may not be able to do, e.g. if that window was created by third-party code)?

    The full dump file can be found on <location>. The password is <xyzzy>.

    Indeed, what the customer suspected is what happened, confirmed by the dump file provided.

    The code behind the window procedure got unloaded. User­Call­Win­Proc­Check­Wow is trying to call the window procedure, but instead it took an exception. The address doesn't match any loaded or recently-unloaded module probably because it was a dynamically generated thunk, like the ones ATL generates.

    There isn't much you can do to defend against this. Even if you manage to detect the problem and avoid calling Set­Focus in this problematic case, all you're doing is kicking the can further down the road. Your program will crash the next time the window receives a message, which it eventually will. (For example, the next time the user changes a system setting and the WM_SETTING­CHANGE message is broadcast to all top-level windows, or the user plugs in an external monitor and the WM_DISPLAY­CHANGE message is broadcast to all top-level windows.)

    Basically, that other component pulled the pin on a grenade and handed it to your thread. That grenade is going to explode sooner or later. The only question is when.

    Such is the danger of giving your application an extension model that allows arbitrary third party code to run. The third party code can do good things to make your program more useful, but it can also do bad things to make your program crash.

  • The Old New Thing

    When designing your user interface, be mindful of the selection-readers

    • 47 Comments

    Occasionally, there will be a feature along the lines of "Whenever the user selects some text, we will pop up an X." And then I have to remind them about so-called selection readers.

    Selection readers are people who habitually select text in a document as they read it. It can be quite maddening looking over the shoulder of a selection reader, because you will see seemingly-random fragments of text get selected, and for those who are selection-deselection readers, the text will almost immediately get cleared. It's like the entire document is blinking with selections. (Other variations of the selection reader are the double-click reader who double-clicks words on the page, the margin-click reader who clicks in the margin, and the hover reader who merely hovers the mouse without clicking.)

    There are a number of theories behind why some people are selection readers.

    • It's a nervous habit to keep one's fingers occupied, similar to spinning a pen.
    • It marks one's place in the document.
    • It gives a sense of accomplishment as one progresses through the document.
    • It helps the eye follow the reading location in the document during a scroll operation.

    I am not a selection reader, but I do click in the document with some regularity. I do this for two reasons.

    1. To give focus to the document area, so that scrolling the mouse wheel or hitting PgDn will scroll the document text.
    2. To place the caret inside the viewport.

    The second reason needs some explanation.

    The caret is the blinking line that shows where your next typed character will be inserted. You can scroll the document so much that the caret goes out of the viewport. For example, if you never click in the document but merely scroll through it, the caret will be at the top of the document, even though you are reading page 25 of 50.

    And then you hit PgDn thinking that you're scrolling down one screen, but instead you're going to the middle of page one. Congratulations, you just lost your place and jumped backward 24 pages.

    Furthermore, there are some programs which are really twitchy about the caret. If you manage to scroll the caret off screen, they will say, "Sure, go ahead and scroll the caret off screen," but then you breathe on the program funny (say, by switching to another program, then switch back with Alt+Tab), and it says, "Whoa, your caret is waaaaay off screen! Let me help you by scrolling the caret back on screen. No need to thank me. Just helping out."

    Of course, what those programs ended up doing is ripping me from page 25 back to page one.

    That's why I consciously click in the document a few times after every scroll operation. It's not yet a habitual operation, so I will sometimes forget, and then just my luck, that's the time I accidentally hit PgDn or or Alt+Tab and get teleported backward in the document.

  • The Old New Thing

    Dubious security vulnerability: Luring somebody into your lair

    • 31 Comments

    A security report was received that went something like this:

    The XYZ application does not load its DLLs securely. Create a directory, say, C:\Vulnerable, and copy XYZ.EXE and a rogue copy of ABC.DLL in that directory. When C:\Vulnerable\XYZ.EXE is run, the XYZ program will load the rogue DLL instead of the official copy in the System32 directory. This is a security flaw in the XYZ program.

    Recall that the directory is the application bundle, The fact that the XYZ.EXE program loads ABC.DLL from the application directory rather than the System32 directory is not surprising because the ABC.DLL has been placed inside the XYZ.EXE program's trusted circle.

    But what is the security flaw, exactly?

    Let's identify the attacker, the victim, and the attack scenario.

    The attacker is the person who created the directory with the copy of XYZ.EXE and the rogue ABC.DLL.

    The victim is whatever poor sap runs the XYZ.EXE program from the custom directory instead of from its normal location.

    The attack scenario is

    • Attacker creates a directory, say, C:\Vulnerable.
    • copy C:\Windows\System32\XYZ.EXE C:\Vulnerable\XYZ.EXE
    • copy rogue.dll C:\Vulnerable\ABC.DLL
    • Convince a victim to run C:\Vulnerable\XYZ.EXE.

    When the victim runs C:\Vulnerable\XYZ.EXE, the rogue DLL gets loaded, and the victim is pwned.

    But the victim was already pwned even before getting to that point! Because the victim ran C:\Vulnerable\XYZ.EXE.

    A much simpler attack is to do this:

    • Attacker creates a directory, say, C:\Vulnerable.
    • copy pwned.exe C:\Vulnerable\XYZ.EXE
    • Convince a victim to run C:\Vulnerable\XYZ.EXE.

    The rogue ABC.DLL is immaterial. All it does is crank up the degree of difficulty without changing the fundamental issue: If you can trick a user into running a program you control, then the user is pwned.

    This is another case of if I can run an arbitrary program, then I can do arbitrary things, also known as MS07-052: Code execution results in code execution.

    Note that the real copy of XYZ.EXE in the System32 directory is unaffected. The attack doesn't affect users which run the real copy. And since C:\Vulnerable isn't on the default PATH, the only way to get somebody to run the rogue copy is to trick them into running the wrong copy.

    It's like saying that there's a security flaw in Anna Kournikova because people can create things that look like Anna Kournikova and trick victims into running it.

  • The Old New Thing

    If you can set enforcement for a rule, you can set up lack of enforcement

    • 9 Comments

    One of the things you can do with an internal tool I've been calling Program Q is run a program any time somebody wants to add or modify a record. The program has wide latitude in what it can do. It can inspect the record being added/modified, maybe record side information in another table, and one of the things it can decide to do is to reject the operation.

    We have set up a validator in our main table to ensure that the widget being added or modified is priced within the approver's limit. But sometimes, there is an urgent widget request and we want to be able to bypass the validation temporarily. Is there a way to disable the validator just for a specific record, or to disable it for all records temporarily?

    If you can set up a program to validate a record, you can also set up a program to not validate a record.

    Suppose your current validator for adding a widget goes like this:

    if (record.approver.limit < record.price) {
     record.Reject("Price exceeds approver's limit");
     return;
    }
    ... other tests go here ...
    

    And say you want to be able to allow emergency requests to go through even though, say, all approvers are unavailable. Because, maybe, the widget is on fire.

    You could decide that a widget whose description begins with the word EMERGENCY is exempt from all validation, but it generates email to a special mailing list.

    if (record.description.beginsWith("EMERGENCY"))
    {
     // emergency override: send email
     // and bypass the rest of validation
     generateNotificationEmail(record);
     return;
    }
    if (record.approver.limit < record.price) {
     record.Reject("Price exceeds approver's limit");
     return;
    }
    ... other tests go here ...
    

    Of course, the EMERGENCY rule was completely arbitrary. You can come up with whatever rules you like. The point is: If you wrote the rules, you can also write the rules so that they have exceptions.

  • The Old New Thing

    Documentation creates contract, which is why you need to be very careful what you document

    • 40 Comments

    A person with a rude name asks, "Why does MS not document the system metrics used by classic/pre-uxtheme windows and common controls? This image is really useful and I wish all of this was actually documented."

    Actually, that picture explains why it isn't documented.

    Suppose such a picture existed in the Windows 2000 documentation. I don't know what it would say exactly, so suppose, for the purpose of discussion, that it said that the caption buttons are exactly SM_CX­FRAME pixels from the right-hand edge of the window, and that the buttons are exactly SM_CX­SIZE pixels wide, with exactly SM_CX­EDGE pixels of padding between the buttons, and the buttons are exactly SM_CY­SIZE pixels tall, with SM_CY­EDGE pixels between the top of the button and the top of the window.

    Once that picture existed in the documentation, the picture you linked to could never exist.

    The picture from Windows 2000 doesn't include the SM_CX­PADDED­BORDER or the the SM_CY­PADDED­BORDER. It can't, because those metrics didn't exist in Windows 2000. Since the diagram is part of the documentation, it is contractual, and it would not be possible to alter the layout of the window caption (say, by incorporating a new metric like SM_CX­PADDED­BORDER), because that would break existing code.

    For example, a program may have looked at the diagram and concluded, "Okay, so if I want to programmatically click the Close button, I can go to the upper right corner of the window, move down SM_CY­FRAME + 1 pixels, move left move down SM_CX­FRAME + 1 pixels, and click there, and it will hit the button."

    And then Windows Vista shows up, adds some SM_CX­PADDED­BORDER between the Close button and the right edge, and the program stops working.

    Publishing the redlines would force the visual layout to be locked in stone. Windows 95 could not have added the Close button. Windows Vista could not have added extra padding around the buttons.

    Note that changing the visual layout of the caption does not break programs which draw their own caption bar. They will continue to draw the caption bar their own custom way. If they tried to mimic the Windows 2000 caption bar, then they will continue to mimic the Windows 2000 caption bar, even on Windows Vista. But nobody gets hurt, because the application is doing both the drawing and the hit-testing, so it remains in sync with itself.

  • The Old New Thing

    Wow, they really crammed a lot into those 410 transistors

    • 29 Comments

    A colleague of mine pointed out that in yesterday's Seattle Times, there was an article about Moore's Law. To illustrate the progress of technology, they included some highlights, including the following piece of trivia:

    The Core 2 Duo processor with 410 transistors made its debut in 2002.

    You can see the photo and caption in the online version of the article if you go to the slide show and look at photo number three.

    This is an impressive feat. Intel managed to cram a Core 2 Duo into only an eighth as many transistors as the 6502.

    On the other hand, it does help to explain why the chip has so few registers. There weren't any transistors left!

  • The Old New Thing

    It rather involved being on the other side of this airtight hatchway: Invalid parameters from one security level crashing code at the same security level (yet again)

    • 23 Comments

    It's the bogus vulnerability that keeps on giving. This time a security researcher found a horrible security flaw in Sys­Alloc­String­Len:

    The Sys­Alloc­String­Len function is vulnerable to a denial-of-service attack. [Long description of reverse-engineering deleted.]

    The Sys­Alloc­String­Len does not check the length parameter properly. If the provided length is larger than the actual length of the buffer, it may encounter an access violation when reading beyond the end of the buffer. Proof of concept:

    SysAllocStringLen(L"Example", 0xFFFFFF);
    

    Credit for this vulnerability should be given to XYZ Security Labs. Copyright © XYZ Security Labs. All rights reserved.

    As with other issues of this type, there is no elevation. The attack code and the code that crashes are on the same side of the airtight hatchway. If your goal was to make the process crash, then instead of passing invalid parameters to the Sys­Alloc­String­Len function, you can launch the denial of service attack much more easily:

    int __cdecl main(int, char**)
    {
        ExitProcess(0);
    }
    

    Congratulations, you just launched a denial-of-service attack against yourself.

    In order to trigger an access violation in the Sys­Alloc­String­Len function, you must already have had enough privilege to run code, which means that you already have enough privilege to terminate the application without needing the Sys­Alloc­String­Len function.

    Once again, we have a case of MS07-052: Code execution results in code execution

    Earlier in the series:

    Bonus bogus vulnerability report:

    The Draw­Text function is vulnerability to a denial-of-service attack because it does not validate that the lpchText parameter is a valid pointer. If you pass NULL as the second parameter, the function crashes. We have found many functions in the system which are vulnerable to the same issue.

    ¹ Now, of course, if there were some way you could externally induce a program into passing invalid parameters to the Sys­Alloc­String­Length function, then you'd be onto something. But even then, the vulnerability would be in the program that is passing the invalid parameters, not in the Sys­Alloc­String­Length function itself.

Page 2 of 98 (973 items) 12345»