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