By Andrew Schulman ------------------------------------------------------------------------ In response to Unauthorized Windows 95, Microsoft now claims that the architecture of Win95 really doesn't matter. For example, Rogers Weed, a group product manager for Win95, told Computer Reseller News (January 2, 1995) that "I don't think [the architectural details] make a difference to most customers." But if Win95s relationship to DOS doesn't matter, why has Microsoft claimed that Win95 eliminates DOS, that it is a brand new "integrated" operating system, and so on? Clearly, because the architecture of Win95 does matter to users and developers. Recall Microsoft's claim about Win95: "Windows 95 isn't a layer on top of MS-DOS.... If an errant application or component goes down everything continues to run." The idea is that Win95's architecture makes it significantly more robust than Windows 3.x. But it then follows that, if this architecture isn't what Microsoft says it is, the implications for Win95's robustness may be quite significant for consumers and developers who are about to choose their next operating system. Perhaps even if Win95 isn't what Microsoft claims, it's still the right choice for most consumers and developers. But even so, that choice ought to be made with all the facts available. Let's discuss some very practical areas where the architecture of Win95 makes a difference. DOS Memory Usage Because Win95 still rests on top of DOS, it relies on DOS memory: the so-called conventional memory below one megabyte. While almost all memory allocation by Windows programs comes out of extended memory above one megabyte, nonetheless every single Windows program -- even the newest Win32 program -- does still require a small amount of conventional memory, to hold a DOS data structure called the Program Segment Prefix (PSP). Every running Windows program must have a PSP. This structure is only about 300 bytes, but those bytes must come out of the memory below 1 MB, so that they can be visible to MS-DOS. Besides undermining Microsoft's claims that DOS is gone from Win95, that each Windows program has a DOS PSP also means that Win95 can get wedged into "out-of-memory" situations, simply because all DOS memory below 1 MB has been allocated. If you try to start a Windows program when no DOS memory is available for the programs PSP, you generally get either the message "A device attached to the system is not functioning" (huh?), or the only slightly clearer "There is not enough free memory to run this program." You can have megabytes of free extended memory, but if there isn't any DOS memory free, you cant start up any more Windows programs. But why wouldn't there be sufficient DOS memory? Most Windows programs only need about 300 bytes of DOS memory for their PSP (they're just a little bit DOS-dependent, in somewhat the same way that one can be "just a little bit pregnant"). Why wouldn't there be any left? Because there is a documented Windows API, GlobalDosAlloc, for allocating conventional memory. There's also a documented DPMI function, INT 31h AX=0100h (Allocate DOS Memory Block). That these calls are documented is important: it means that any Windows app can legally allocate DOS memory. There is also a documented VMM service, callable by VxDs, to allocate DOS memory. Given three different documented interfaces for allocating DOS memory, and given a maximum of one megabyte of DOS memory, it's hardly surprising that Windows 95 can run into insufficient DOS memory system-resource problems. If you want, you can experiment with this problem using the DOSMEM program available on O'Reilly's Web site. Protected from DOS? Here's another very practical implication of the fact that Win95 still rests on DOS: you can crash all of Win95 from a DOS program. Heres a one-line DEBUG command that fills the lower 64k of memory with 0: f 0:0 ffff 0 And here's how that same operation looks in C: _fmemset((char far *) 0, 0, 0xffff); Yes, this is buggy code. But Adrian King's semi-official Inside Windows 95 (p. 56) states that "There has to be a way to prevent applications from maliciously or inadvertently corrupting the operation of the system." Yet, our one-line DEBUG command does not merely kill off the DOS box in which it is run. That would be entirely acceptable. Instead, this easy-to-reproduce example crashes all of Win95, taking with it whatever Win16 or Win32 programs you're working with at the time. That Win95 is so vulnerable to buggy or malicious DOS programs is particularly surprising, because Microsoft has gone to the trouble of providing an MS-DOS "Protection" option. This is a flag that you can set via "MS-DOS Prompt Properties" / "Memory" on the DOS box's system menu. Unfortunately, this feature only protects some of MS-DOS; even with "Protection" enabled, the DEBUG command shown above still crashes all of Win95. Introducing Microsoft Windows 95 (p. 60) asserts that "In Windows, VMs are fully protected from one another, as well as from other applications running on the system. This protection prevents errant MS-DOS-based applications from overwriting memory occupied or used by system components or other applications." Clearly, this is untrue. But if a DOS program such as DEBUG runs in its own "virtual machine," how can it crash Windows applications, which run in their own separate "System VM?" Easy. While each VM does for the most part have its own separate address space, there is also a global area shared by all VMs. This global area represents memory that was allocated before Windows started up, that is, memory belonging to DOS, to real-mode device drivers such as HIMEM, IFSHLP, DRVSPACE, and so on. This area is required by Windows itself, whether or not you run any DOS apps. In addition, the Windows Virtual Machine Manager (VMM) provides a function, documented in the Windows Device Driver Kit, called _Allocate_Global_V86_Data_Area. As its name implies, this function allows VxDs to allocate "global" memory in the Virtual-8086 address space: memory that is located below 1MB and that is visible to all VMs. Key VxDs such as DOSMGR, VSHARE, IFSMGR, IOS, and SHELL use this service to allocate global buffers below 1MB. These buffers are at the mercy of DOS programs. Note in particular the presence of data for the file system (IFSMGR is the Installable File System Manager) and the disk (IOS is the I/O Supervisor). At the same time, there are plenty of areas below 1MB that a DOS app can freely overwrite, but that won't bring down all of Windows. Each VM also has "local" memory below 1MB; this corresponds to conventional memory that was free before Windows started up. For example, some key parts of the Win16 KERNEL are temporarily located below 1MB. While these areas are still at the mercy of buggy Win16 or Win32 programs, at least they are inaccessible to programs running in DOS boxes. Microsoft's complacent attitude toward protecting system code in Win95 is odd because it has in the past fully recognized the importance of protecting the DOS system code. According to Introducing Microsoft Windows 95 (p. 86), in Windows 3.1, "the VMs did not completely prevent an MS-DOS-based application from overwriting MS-DOS system code." Presumably, then, such complete prevention is important. However, Win95 no more provides this complete protection than did Windows 3.1. The Dangerous Memory Model Now, if a DOS program can crash Win95, what about a Win32 program? These according to Microsoft are supposed to be particularly robust: "Each Win32-based application runs in its own private address space which prevents that Win32-based application from inadvertently overwriting the memory area of another application or of the system as a whole" ( Introducing Microsoft Windows 95, p. 89). That phrase, "of the system as a whole" is important: Win95 is supposed to prevent errant Win32 applications from overwriting the system. If a Win32 program tries to overwrite part of Win95 itself, a general-protection (GP) fault should be generated, and the program shut down, thereby protecting whatever work you're doing in other programs. It's easy to test this by attempting to overwrite DOS conventional memory from a Win32 program. There isn't a Win32 version of the DOS DEBUG program, but it's easy to duplicate DEBUGs "f" (fill) command in a Win32 program. FILL.C is a small Win32 program that uses the C memset function to fill with zeroes any area you designate on the command line. Well, tries to fill. If you run FILL 0 FFFF, which is the Win32 equivalent of the DEBUG command shown earlier, nothing bad happens under Win95. FILL prints out the message "Protected!," indicating that Win95 prevented the attempted memory overwrite from occurring (FILL uses the Structured Exception Handling (SEH) _try and _except statements to detect this). This is exactly what we want in the "modern" operating system that Win95 claims to be. Well, not exactly. Win95 seals off only about the first 64K of memory from Win32 applications. You can just as easily bring down Win95 from a Win32 program by zeroing memory somewhere else in the first 1MB. And, as we saw above, the first 64K is still stomp-able from any DOS app. And, finally, it's worth noting that the first 64k almost never includes DOS itself: when running with DOS=HIGH (the default in Win95), DOS is located in the high memory area (HMA) just above one megabyte, and can be corrupted by a Win32 program. Trashing System Memory As one example, running FILL 10000 FFFF instantly crashes Win95. So much for Microsoft's claim that Win95 "prevents" Win32 programs from inadvertently overwriting the memory area "of the system as a whole." Now, Microsoft does specify "inadvertently," but this is a weasel word: if Win95 truly prevented Win32 programs from inadvertently trashing system memory, it would also prevent programs such as FILL from deliberately trashing system memory. What is it trashing when a Win32 application overwrites conventional memory? Of course, there are the same global areas (MS-DOS, DOS device drivers such as IFSHLP and DRVSPACE, and global V86 data areas belonging to VxDs such as VSHARE, IFSMGR, IOS) that, as we saw earlier, a DOS app can inadvertently or deliberately trample on. However, recall that large parts of conventional memory -- local and instance data -- are separate in each VM, so a DOS program can only step on certain parts of the conventional memory used to run Windows applications. This barrier unfortunately is not present for Win32 (or Win16) programs. These programs run in the System VM, which also contains much of the Windows system code (KERNEL, USER, GDI, and so on). Perhaps surprisingly, some of this crucial system code is located below 1MB, in local conventional memory belonging to the System VM. Win95 also locates crucial system data -- such as the Win16Lock and the KERNEL32 thunk table -- in DOS memory below 1MB. In general, a major problem in Win95 is its continuing reliance on conventional memory below 1MB. This memory is vulnerable to attack (whether inadvertent or deliberate) from a Win32 program. Leaving aside the question of why parts of the KERNEL are located in DOS memory, when Win95 is supposed to be a brand-new operating system that doesn't rely on DOS -- probably it has to do with the original 4MB memory requirements for Win95, which clearly have not been met, despite what the Win95 box say -- how is it that a Win32 program such as FILL can so easily blast DOS conventional memory? Quite simply, because Win95 maps the first 1MB (with the exception of the first roughly 64K) into the address space of every single Win32 process. This memory is both readable and writeable, and a Win32 program can easily access it simply by forming a pointer to it. This is worse than the situation with Win16 applications, which generally needed to explicitly ask Windows or DPMI to look at this memory. The Win32 address space under Win95 has been referred to as the "Dangerous Memory Model" (DMM), borrowing a phrase coined a few years ago by Richard Smith of Phar Lap Software to designate a popular memory architecture for DOS extenders. Win95 has this same DOS extender architecture, and probably for much the same reason: it's convenient for the systems developers (the technical term for this is "ease of implementation"). But Win95 doesn't just give each Win32 process full read/write access to most of the shared lower 1MB of memory. Win95 also gives each Win32 process full read/write access to many other crucial parts of the system. You can download a Win32 program called MEMPROBE from O'Reilly's Web site that walks through the entire 4 gigabyte address space, using the _try and _except SEH statements to see which portions are writeable; the program writes the same bytes as it reads, so it doesn't do any damage. Out of 4 gigabytes, in a variety of configurations MEMPROBE reveals between 25 and 60 megabytes (roughly 1%) of system memory that is writeable by Win32 programs. Private Address Spaces? Not! This makes a mockery of Microsoft's claim that each Win32 process in Win95 has its own "private address space." Yes, large portions of the address space are private, but there are large, gaping holes. This is similar to the way in which VMs are only partially private. Win95 private address spaces are riddled with bullet holes. Amazingly, even the memory context data structures, used to maintain private address spaces, are writeable by any Win32 program! How big are these holes? As noted above, MEMPROBE reveals that, depending on the configuration, roughly 1% of the 4 gigabyte address space is writeable by a Win32 process. To see how it compares with other operating systems, you can download another program from our web, RANDRW, which runs not only in Win95, but also in Win32s, OS/2, Windows NT, and Phar Laps TNT DOS extender. RANDRW attempts one million writes to random locations in memory, and counts how many of these writes were successful. Like MEMPROBE, RANDRW writes the same data as it reads, so it doesn't do any damage. Here is the percentage of attempted random memory writes that succeeded in various operating systems, as measured by RANDRW: Win95; 32 bit; 1 DOS box .50 Win95; 32 bit; 6 DOS boxes 1.07 Win32s; 3 DOS boxes .72 Win95; 16 bit .26 OS/2 .14 Phar Lap TNT .01 Windows NT .005 For example, out of one million attempted random writes on Win95, with 6 DOS boxes running, about 10,700 succeeded; the rest caused GP faults, of course, just as one wants. In Windows NT, only about 50 succeeded; in OS/2, about 1,400 succeeded. This gives a good idea, I think, of the relative memory protection of these systems. The OS/2 figure, while better than that turned in by Win95, would probably surprise most OS/2 advocates. We already know that the lower 1MB of memory is used for parts of the system such as DOS, DOS device drivers, the VxD V86 data areas, and parts of the Win16 heap. What's in the other areas that are writeable by Win32 programs? Some of the important areas are: * Page directory * Global Descriptor Table (GDT) * Local Descriptor Table (LDT) * Interrupt Descriptor Table (IDT) * Task State Segment (TSS), including the I/O Permission Bitmap * Four-megabyte "high linear" address space of each VM; thus, each DOS box is mapped into each Win32 process! * VMM and the VxDs; this includes all the IOS and IFSMGR VxD routines related to files and disks. * Memory-mapped files * Pieces of the file cache * Memory context data structures In a robust OS, accessing such vital areas would cause a GP fault: annoying to the user, perhaps, but closing down a single app is clearly preferable to crashing the entire system. Such a crash not only loses the work in all your running apps, but -- since Win95 aggressively caches file data -- also could cause permanent data loss. Furthermore, because the file cache is mapped into, and is changeable by, Win32 apps, there's the potential for bugs in Win32 apps to result in permanent data corruption. Unfortunately, then, while "multitasking robustness" has dramatically improved over Windows 3.1, -- it's more difficult for an uncooperative Windows program to hang the system now -- memory protection in Win95 is still feeble. In too many situations where Win95 should shut down an application, instead it lets a buggy (or worse, deliberately malicious) application do what it wants. At the same time, it's worth noting that the Dangerous Memory Model can be exploited in useful ways by Win32 programs. You can download some interesting programs that illustrate this from our Web site. For example, VXDCHAIN.C is a Win32 program that directly accesses VxD memory. It's frightening to think that a "buggy" Win32 program could be accidentally walking all over Win95s file cache, but there are some interesting possibilities for developers who want to do the otherwise-impossible in their Win32 programs. Ultimately, the reason why the architecture of Win95 matters can be summed up with a single word: clarity. Our industry wastes too much time because of poorly-understood technology. Only by seeing clearly how dominant products such as Win95 actually work can we make intelligent decisions about what software to use and develop. Armed with a clear picture of how Windows works, developers can perform magic. ------------------------------------------------------------------------ Return to Windows 95 ------------------------------------------------------------------------