The NT Insider
Transcription
The NT Insider
® Page TM 1 The NT Insider The only publication dedicated entirely to Windows® system software development A publication by OSR Open Systems Resources, Inc. Not endorsed by or associated with Microsoft Corporation. January — February 2009 Volume 16 Issue 1 Common Topics Happy 2009? Deferred Procedure Call Details D eferred Procedure Calls (DPCs) are a commonly used feature of Windows. Their uses are wide and varied, but they are most commonly used for what we typically refer to as "ISR completion" and are the underlying technology of timers in Windows. If they're so commonly used, then why are we bothering to write an entire article on them? Well, what we've found is that most people don't really understand the underlying implementation details of how DPCs work. And, as it turns out, a solid understanding is important in choosing the options available to you when creating DPCs and is also a life saver in some debug scenarios. Introduction This article is not meant to be a comprehensive review of why or how DPCs are used. It is assumed that the reader already knows what a DPC is or, even better, has used them in a driver. If you do not fall into this category, information at that level is readily available on MSDN. In addition, Threaded DPCs, which are a special type of DPC available on Windows Vista and later, will not be covered in any detail. As a basis of our discussion, let's briefly review some basic DPC concepts. A working definition of DPCs is that they are a method by which a driver can request a callback to an arbitrary thread context at IRQL DISPATCH_LEVEL. The DPC object itself is nothing more than a data structure with a LIST_ENTRY, a callback pointer, some W ell, that remains to seen for many folks, regardless of the industry. Profits are down, job losses are up, belts are being tightened...all is not right in the world. For those of you who are not aware, OSR provides job forums for both those companies looking to hire permanent, experienced driver developers, and of course, those looking to be hired by said companies. Check out Driver Jobs in the left-hand navigation menu at OSR Online (www.osronline.com). If you’re still gainfully employed, great. If you’re not, rest assured The NT Insider will still keep coming your way. (Continued on page 12) Why Take An OSR Seminar? Whether you want to learn kernel debugging techniques, or you crave in-depth kernel device driver or file systems knowhow, OSR has a specific solution tailored precisely to the type of training you need. Who are your instructors? Make no mistake about it, when you take an OSR seminar, you’ll be learning from the best. First of all, OSR isn’t a “training company.” We are consultants. Senior developers. Development leads on actual, cutting-edge projects developing system software. As your instructors, they bring you real-world answers to questions that textbooks – or other seminars – simply can ’t answer. We train more engineers in the design, development and debugging of Windows kernel-mode software than any other company. Period. Check out the latest seminar schedule on the back of this issue, or visit us on the web at www.osr.com. Interested in a customized, on-site presentation for your team? Drop us an email ([email protected]) and we’ll work with you to custom tailor one of our presentations for your needs. We can even schedule an extra day of consultancy to answer specific questions relative to your current project! Page 2 The NT Insider™ Published by Inside This Issue: OSR Open Systems Resources, Inc. 105 Route 101A, Suite 19 Amherst, New Hampshire USA 03031 (603) 595-6500 Common Topics — Deferred Procedure Call Details 1 http://www.osr.com New WDK for Win7: TRY IT NOW! 3 Peter Pontificates: Computer Programming Has Ruined My Brain 4 Filtering File Systems — Ten Things You Should Know 6 Safety First — Using the Windows String Safe Functions 8 How to Fetch Checked Components for Vista/Server 2008 18 Who Was at the DDC? Well, We Were, But… 19 Consulting Partners W. Anthony Mason Peter G. Viscarola Executive Editor Daniel D. Root Contributing Editors Mark J. Cariddi Scott J. Noone OSR Associate Staff Consultant At Large Hector J. Rodriguez Send Stuff To Us: email: [email protected] fax: (603) 595-6503 Single Issue Price: $15.00 The NT Insider is Copyright ©2007. All rights reserved. No part of this work may be reproduced or used in any form or by any means without the written permission of OSR Open Systems Resources, Inc. (OSR). We welcome both comments and unsolicited manuscripts from our readers. We reserve the right to edit anything submitted, and publish it at our exclusive option. Stuff Our Lawyers Make Us Say All trademarks mentioned in this publication are the property of their respective owners. “OSR”, “The NT Insider”, “OSR Online” and the OSR corporate logo are trademarks or registered trademarks of OSR Open Systems Resources, Inc. We really try very hard to be sure that the information we publish in The NT Insider is accurate. Sometimes we may screw up. We’ll appreciate it if you call this to our attention, if you do it gently. OSR expressly disclaims any warranty for the material presented herein. This material is presented “as is” without warranty of any kind, either expressed or implied, including, without limitation, the implied warranties of merchantability or fitness for a particular purpose. The entire risk arising from the use of this material remains with you. OSR’s entire liability and your exclusive remedy shall not exceed the price paid for this material. In no event shall OSR or its suppliers be liable for any damages whatsoever. It is the official policy of OSR Open Systems Resources, Inc. to safeguard and protect as its own, the confidential and proprietary information of its clients, partners, and others. OSR will not knowingly divulge trade secret or proprietary information of any party without prior written permission. All information contained in The NT Insider has been learned or deduced from public sources...often using a lot of sweat and sometimes even a good deal of ingenuity. Neither OSR nor The NT Insider is in any way endorsed by Microsoft Corporation. And we like it that way, thank you very much. OSR Seminar Schedule Mini-filter driver development—Boston, MA WDF driver development—Portland, OR Kernel Debugging — Portland, OR WDM driver development—Boston, MA File systems development—Boston, MA See Back Cover for Dates Page 3 New WDK for Win7: TRY IT NOW I f you haven't done so, do make some time to install, examine, and actually play with the Beta version of the Win7 WDK. You can download it right now from Microsoft Connect (http://connect.microsoft.com). If you're not already on the WDK Beta list, you can use invitation ID OSR-GMVB-T9HX to join (enter this invitation ID in the " Wer e you invited to join Connect?" box on the right of the home page). We know you're almost certainly busy doing work that's not related to Windows 7. So are we. But, here's the thing: Your chance to influence what's in the Win7 WDK is now, not months from now when you've started to work on Win7 stuff. You might be surprised at some of the things you find. Some good, some that may make you wonder. For example: There's a new Office Automated Code Review tool that will automatically run PreFast on your driver for you. The Windows 2000 Build Environment has ceased to be. It is no longer. It has gone to meet its maker. There have been some changes to the SOURCES file syntax The legacy file system filter driver samples are gone These are just a few things that we noticed. Are these things good? Well, here at OSR we're not particularly happy about the disappearance of the Win2K Build Environment, for example. But the point isn't what we think (we've already provided the WDK team with our thoughts)... The point is what do you think about these things.? And what will you notice that you like or dislike, that you find useful or problematic, about the Beta version of the Win7 WDK? If you don't install it, you won't know. So, go get the WDK, install it, and give it a run-through. And provide feedback to the W DK team about your experience. You complain that Microsoft doesn't listen to you? Well, we've heard the WDK team ask for feedback repeatedly -- both publically and privately -- on the Win7 WDK Beta. The best way to provide feedback is via the Win7 WDK feedback form on Microsoft Connect. This form is specifically (and only) for WDK bugs -- not Win7 O/S bugs. The WDK team has told us that this is the "express pipeline" directly to them for Win7 WDK Beta comments and bug reports. Alternatively, you can send feedback by email to [email protected]. Design & Code Reviews Have a great product design, but looking for extra security to validate internal operations before bringing it to your board of directors? Or perhaps you’re in the late stages of development of your driver and are looking to have an expert pour over the code to ensure stability and robustness before release to your client base. A small investment in time and money in either service can “save face” in front of those who will be contributing to your bottom line. OSR has worked with both startups and multi-national behemoths. Consider what a team of internals, device driver and file system experts can do for you. Contact OSR Sales — [email protected]. Page 4 Peter Pontificates: Computer Programming Has Ruined My Brain J ust a confirmation ladies and gentlemen: this is Alaska Airlines flight 15 non-stop to Seattle. Please move down the aisle to your seats as quickly as possible, so we can be underway without delay. Please remember that the primary storage location for your luggage is under the seat in front of you. As this is a very fully flight… I hadn't really been paying attention to the background blather, but my mind just sort of locked-in on that last statement. Did she say "a very full flight"? Huh? I turn to my seat mate, a skinny dude with glasses trying very hard to make sure everyone knows he is a medical doctor, because of his superior manner, the non-stop use of his cell phone to talk about his patients in a loud voice, and his constant waving of a copy of Journal of Clinical Oncology. Me: Did she say " ver y full flight" ? Dr Boy: (looking over his Dolce and Gabbana glasses) Excuse me? Me: Ver y full. Did the flight attendant just say it was a "very full flight"? Because, well I don't really understand how that can be, given that "full" is a boolean. It means "filled to capacity." The flight can be FULL or NOT FULL. It can't be VERY FULL. Dr Boy: Uh, uhm... I' m not sur e (waves Oncology Journal)... Stewardess! (orders a scotch, while ostentatiously making another phone call) I can't stand stuff like this. Stuff like people acting highly superior on planes (jet travel is soooo glamorous these days, don't you think?) of course, but that's not what I specifically mean in the context of this article. I mean booleans being used as floating points. If full is a boolean, it can only be TRUE or FALSE (or true or false if you're with me on that C# thing from last year, but I digress). It can't have any other value. So how could the plane be very full? As I considered this, and noticed the stares I was still getting from Dr Boy out of the corner of his eye, I started to worry about my health just a bit. After I thought about it for a while, I came to a realization: Computer programming has ruined my brain. I suppose I knew this even before I had the above described revelation on the tarmac. It was just the other day that I was looking for scheduled episodes of a particular TV show with my DVR that I was driven into a fit of pique. I did "Search for shows" and then "By title." I entered "House" (the show title). The search results display page had three columns that read as follows: House House House House 21 Jan 21 Jan 23 Jan 23 Jan 8:00PM 9:00PM 2:00AM 9:00PM USAHD USAHD HDNet USAHD House 26 Jan 8:00PM FoxHD As an aside, please note that this was not a TiVo. TiVo is great. TiVo is the highest form of its art. There's nothing wrong with anything that TiVo does. There is probably not even anything wrong with anything made in Alviso California, in fact. I was using a different, low-rent, knockoff, ghetto, poseur TiVo wanna-be DVR. Obviously. What drove me nuts -- insane, in fact -- about the results display was that it showed the title of the show on each line... but failed to show the episode name. I already knew the name of the damn show. I was searching by title, right? Showing the title was useless. My wife was sitting with me: Me: Ar r gh. Why ar e they showing me the T itle field? Karen: Huh? It's the title of the show. Me: I know that. But why ar e they showing it to me? On the search results page. Why didn't they show me the Episode name? I mean, heck... we've seen "House's Head" like three times... but we missed "Wilson's Heart." Karen: Cuz that's what they show. So you'll know the title. So… Me: I searched by title. I k now the title. I'll tell you why they show it. It's because the dev was too lazy to code a separate page for each search result type, that's why. If she had coded a search results (Continued on page 5) Learn KMDF from Experts Why wouldn’t you? If you’ve got a new device you need to support on Windows, you should be considering the advantages of writing a KMDF driver. Hands on experience with labs that utilize OSR’s USB FX2 device make learning easy and you get to walk away with the hardware! Contact our seminar [email protected]. coordinator at Page 5 Computer Programming... (Continued from page 4) page for "search by title" that showed the episode name, and a separate search results page for "search by actor" or whatever that showed the show title, that would have been more work. Seriously, this is just a bunch of HTML and how much time would it have taken? Probably less time than it will now take me to select each of the results from the search results page and see what the episode title is. Karen: You just click on it.. Me: I know I just click on it. But why was it written this way? It's freakin' idiotic. If one of the devs who works with me did that, they'd be fired. It's either lazy or it's stupid… Karen: I' m going to get a cup of tea. Let me know when you're done talking to the dog about how the TiVo works and there's something for us to watch. Me: Ar r r gh... It's not a T iV o, it's a cheap-ass offbrand TiVo clone… Karen: (fr om the kitchen now, with the teapot) uh huh, yeah, TiVo, yup. Come here Toby! She was familiar with this type of tirade. It was similar to the one I loosed when I didn't like the fact that her new car navigation system required you to go 7 menus deep in order to set what I figured should be a common parameter. That tirade contained a long soliloquy starting with "Who writes software like this?" and ending with"...would be fired" and "... either lazy or stupid." accept the bad design choices. The really awful implementation decisions. The just plain dumb code. I wish that I could report that the spongiform that is computer programming had only affected my brain in the use of consumer electronics products. Sadly, this is not the case. It's affected just about everything I do. Recently, my dog got sick. On one of my visits to the vet, I made him sit down and put the various treatment options into "if... then... else..." statements. He thought I was, shall we say, rather unusual . I thought he had a very disorganized way of thinking. How does somebody work in an office that doesn't even have a white board! It's ridiculous. I wanted to find another vet -not really trusting anyone who doesn't have an immediate grasp of C syntax or Expo markers -- but Karen talked me out of it. Anyhow, at least now I realized my malady. And as I sat on the plane, getting ready to take off, I rolled the whole thing over in my mind. Maybe it wasn't so bad to be infected by computer programming. At least it kept me from speaking loudly on my cell phone and waving an oncology journal at the flight attendant. Hmmmm... I wonder who wrote the software that does the avionics displays? Peter Pontificates is a regular opinion column by OSR consulting partner, Peter Viscarola. Peter doesn’t care if you agree or disagree, but you do have the opportunity to see your comments in a future issue. Send your own comments, rants, or distortions of fact to: [email protected] If I didn't know how to program, I don't think these things would bother me. I'd probably just accept "that's the way that the DVR works" and probably be amazed that the damn thing knew when every episode of House was scheduled for the next two weeks. I'd be blissful in my ignorance. But, computer programming having ruined my brain, I couldn't OSR Software Development—Experience, Expertise and Guarantee In times like these, you can’t afford to hire a fly-by-night Windows driver developer. The money you think you’ll save in hiring cheap help by-the-hour, will disappear once you realize this trial and error method of development has turned your time and materials project into a lengthy “mopping up” exercise...long after your contract programmer is gone. Consider the advantages of working with OSR. If we can be of value-add to your project, we’ll tell you—if we can’t we’ll tell you that too. You deserve (and should demand) definitive expertise. You shouldn't pay for inexperienced devs to attempt to develop your solution. What you need is fixed-price solutions with guaranteed results. Contact the OSR Sales team at [email protected] to discuss your next project. Page 6 Filtering File Systems Ten Things You Should Know R egardless of whether you are still supporting legacy file system filter drivers, or maintaining or building new minifilter drivers, there are some common techniques (ok, there are only nine…) you can use to improve the robustness of your filter. Many of these are pragmatic – they are not things you will read in the documentation, they come from experience working with filters for many, many years. Never Trust Buffers Filter drivers are forced to endure a remarkably hostile environment, both from their neighbors (other filter drivers) as well as those that are inherently untrusted (any user mode code). A single mistake in a file system filter driver can create a potential “time bomb” waiting to happen. User Buffers are the most commonly identified “risk factor” when it comes to buffer management. Despite that, we still routinely see filters that fail to take the two necessary steps for protecting against user buffers. First, you must ensure that a user buffer really is within the user portion of the address space. This is performed by probing the address, normally using ProbeForRead or ProbeForWrite. Probing a user buffer only ensures it is in the user’s address space, however. If it is invalid at that point in time the probe will work, but this call does nothing to ensure the address remains valid. Thus, the second key part of buffer handling is to ensure any access to it is protected with a structured exception handler. Microsoft provides their own custom handler and it is invoked using special extensions implemented by the C compiler used in the WDK environment. This is done using __try and __except. Both of these steps are essential to ensuring correct user buffer handling. In addition, file system filter drivers must deal with the pragmatic issue that they may be handed invalid kernel data structures. The harsh reality is that it is not uncommon for other kernel components to pass along invalid structures. Mini-filters are somewhat protected against this, since invalid structures passed into filter manager will cause filter manager to crash, not the mini-filter. Despite this, if you are the only mini-filter on the system it won’t crash without your filter and it will crash with your filter (and we all know that this means it must be “your fault”). Thus, what we generally suggest– as much as possible – is to carefully validate your own data structures. While not guaranteed, we’ve used this technique to detect erroneous situations numerous times. In our experience it is better to use “deprecated” functions like MmIsNonPagedSystem AddressValid (which is of dubious value) to add even a modest amount of robustness to our code. This is pragmatic – if the system crashes in our driver, we will be blamed for the crash. If we can instead return an error and it crashes in another driver, it will become the problem of that other driver writer. Remember, when someone types “!analyze –v”, it will blame the first non-Microsoft driver on the stack. Hence, it’s better to not be on the stack, at least from a support overhead burden. Validate Parameters Sure, we all know that it isn’t necessary to validate buffers that are passed to us by other kernel mode components, but only Microsoft has the luxury of this type of magic thinking. For the rest of us, it really is vital to keep in mind that the system is not static and we are constantly forced to “figure out” why things are not working. Keep in mind when validating any information: Buffers are not static. You do not own the only reference to that buffer and they can (and do) change. If you want to rely upon the contents of buffers, you must capture that information (if it changes inside a private captured buffer, it’s called “memory corruption” and not a buffer handling error!) With Windows Vista, MDLs that arrive in your filter can include “dummy pages”. These pages can create potential confusion for any filter that tries to modify the data (e.g., an encryption filter) because that buffer’s content is not static. This merely reinforces our observation before – if you want static content, capture it and operate on it separately from the original. If you decide to switch around the MDLs in an I/O request, don’t forget to also update the UserBuffer field (the file systems rely upon this being “correct” – which means it must be the same virtual address that is in the MDL passed). Beware the Failure Cases Over the years, we have consistently observed that developers are, as a group, remarkably optimistic. This shows in their coding, which tends to assume that everything is going to work properly. As it turns out, however, this optimism is unwarranted – and the source of frequent bugs. Further, as your driver is more widely deployed, you will observe a greater number of these failure scenarios. Indeed, in our experience, even mature code bases will experience “we’ve never seen this failure case before” scenarios. Naturally, the fact that it is almost impossible to test all of these failure scenarios further complicates writing code to handle those cases. Nevertheless, it is important for file system filter driver writers (both legacy and mini-filter writers) to think about error cases and handle them. (Continued on page 7) Page 7 Filtering... (Continued from page 6) In general, we’ve noticed a few classes of such failures: Allocation failures. These are quite common, but something often overlooked is that handling allocation failures at the point you need the allocated object is frequently “too late” to handle the error gracefully. Generally, we suggest moving the allocation to an earlier point in the code – keeping in mind that freeing an object won’t fail. So, in a mini-filter (for example) we allocate our data structure for our context tracking information in the pre-create path, even though we won’t use it until the post-create path. If we don’t need it, we free it. In the pre-create path, however, we can gracefully return an error. In post-create, we are forced to try and cancel the file open (which is far more complicated and subject to errors). Connection failures. While we’ll mention redirectors “later”, we have noticed that timeouts and disconnections are common enough failures that just aren’t handled. If you use a service, you have to consider what your driver will do when it fails, not to mention how it fails. Nothing is worse for a user than the frustration of having an operation (in your filter) hang forever waiting on a service that has entered an infinite loop. Unwinding failures. These are perhaps the most insidious of the error handling cases. You’ve done your job and checked for a specific error case. But you have already done operations that need to be undone. Thus, your error handling code must then attempt to undo something you’ve already done. It could be as simple as changing the read-only bit on a file, or as complicated as changing its ACL. Some later step fails and you attempt to set it back – but that attempt to unwind itself fails. Of course, our point is not to provide some complete list, but rather to point out that when writing code, and particularly when code reviewing it, try looking through it and ignoring the “everything works right” cases and look at the “everything comes unraveled” cases. After all, the “everything works right” case is by far the most likely case to be tested and fixed quickly. Avoid Changing File Sizes The most difficult filters to build and maintain are those that change the size of the underlying file and then try to mask this behavior from the applications. There are very good reasons for masking these changes from applications – after all, applications rely upon the size information in the directory entry being correct. For example the “verify” option for xcopy (“/v”) actually looks at the size in the directory entry, not in the file itself. Exacerbating this issue is that directories can be surprisingly large (we’ve received bug reports against directories with over 700,000 entries in a single directory – so large that the owner of that large directory could not enumerate it with Explorer and instead only enumerated it from the command line!) If you have to actually open the file in order to retrieve the file size, it will make directory enumeration dramatically slower. In our experience, unless you implement caching, the cost of “correcting directory entry sizes” has an amazing impact – it effectively makes doing almost anything with high access directories impossible (e.g., “\Windows”). Underlying this is the fact that application programs are sloppy – they use information that is demonstrably not updated (NTFS, for example, only updates the size in the link used, so this size from the directory entry trick can be spoofed by using a link to change the file size). We have seen people try to use “naming tricks” to resolve this issue. Fair warning: whenever you think you have a clever solution in a filter driver, ask yourself “and how will this work when someone else implements a filter driver that plays the same/similar trick.” If the answer is “it does not work” then you don’t have a viable solution. Name prefix/suffix tricks fall into this category. The best thing to do is to never change size. If you must change the size of the file, the next best trick is to do this only on file systems that support both sparseness and alternate data streams – then you can keep a dummy default stream (“::$DATA” on NTFS) that is the correct size, with the modified data in an alternate data stream. Unfortunately, that often is not a viable solution because it is restricted to only some file systems. In that case, be prepared for building a very complicated filter driver. FSD/MM/CC Interactions Are Complicated We often observe that interactions in this business between the components are horribly complicated (See Figure 1). File system filter drivers sit in the midst of this complex (Continued on page 15) “File and Folder” Encryption Several commercially shipping products are a testament to the success of OSR’s most recent development toolkit, the Data Modification Kit. With the encryption codebase, implement file system hassle of developing transparent file solutions on the rise, why not work with a a support team and a reputation to your encryption or other data-modifying solution? Check out the DMK at www.osr.com, and/or contact OSR to discuss the DMK and your needs to determine if you can take advantage of this unique solution. Phone: +1 603.595.6500 Email: [email protected] Page 8 Safety First Using the Windows String Safe Functions U nless you have had your head in a hole for the last couple of years, you have undoubtedly heard about Microsoft fixing security holes in Windows kernel mode code. Many of the problems they encountered had to do with string handling functions, for example strcat, strcpy, and their related c-runtime library functions (CRT) . The weakness in these functions is that no buffer lengths are specified, so it is very easy for a user to copy a long string into a short buffer and thus corrupt memory or worse, cause some unhandled exception. Buffer overruns have even been used as security attacks. To fix this class of problem Microsoft created a safer set of functions called the "String Safe" Functions. These relatively recent functions (XP SP1), to no one's surprise, add parameters to describe the length of the string buffers, to reduce the chance that buffers are overflowed When Microsoft created the string safe functions they created two sets of functions. One set uses byte counts to describe buffer lengths, while the other set of functions uses character counts to describe the buffer lengths. Byte Count related functions always contain "Cb" (for count in bytes) in the name, for example RtlStringCbCat. The character count related functions always contain "Cch" (for count in char acter s) in the name, for example RtlStringCchCat. The type of function to use is entirely up to you. Now, it is nice to know that Windows provides these functions, and some of the advantages are probably already evident to you. However, let's review some of the major benefits to using these newer functions: Since you are providing the correct size of the destination buffer this ensures that the function will not write past the end of the input buffer. All string safe functions guarantee that the output buffers are null terminated, even if the operation truncates the intended result. All the string safe functions return an NTSTATUS, with the only possible success code being STATUS_SUCCESS (there are, of course, several possible error codes). Each string handling function has both a Cch and Cb variant available for use. Most functions have an extended "Ex" version which provides extended functionality. String Safe Character Count Functions Table 1 lists the character count string safe functions provided in "strsafe.h" and the c-runtime functions (CRT) functions they are intended to replace. String Safe Byte Count Functions Table 2 lists the byte count string safe functions provided in "strsafe.h" and the c-runtime functions (CRT) functions they are intended to replace. Unicode Strings At this point I probably have given you the impression that the string safe functions are only intended to replace c-runtime functions. That is not true. The string safe functions include many functions, of both Cch and Cb variants, to help you with Unicode strings also. The list below contains the functions provided: RtlUnicodeStringXxxCatN, RtlUnicodeStringXxxCatNEx RtlUnicodeStringXxxCatStringN, RtlUnicodeStringXxxCatStringNEx String Safe Functions CRT Functions Replaced RtlStringCchCat, RtlStringCchCatEx RtlStringCchCatN, RtlStringCchCatNEx RtlStringCchCopy, RtlStringCchCopyEx RtlStringCchCopyN, RtlStringCchCopyNEx RtlStringCchGets, RtlStringCchGetsEx RtlStringCchPrintf, RtlStringCchPrintFEx RtlStringCchVPrintf, RtlStringCchVPrintfEx RtlStringCchLength strcat,wcscat,lstrcat,strcat,StrCatBuff,_tcscat,_ftcscat (Continued on page 9) strncat,StrNCat strcpy,wcscpy,lstrcpy,strcpy,_tcscpy,_ftcscpy strncpy gets,_getws_getts sprintf,swprintf,wsprintf,wnsprintf,_stprintf,_snprintf, _snwprintf, _sntprintf vsprintf,vswprintf,wvsprintf,wvnsprintf,_vstprintf,_vsnprintf, _vsnwprintf, _vsntprintf Strlen Table 1 Page 9 String Safe... Cch version of the string safe functions (Figure 2)and the other using the Cb version (Figure 3). As you notice with the Cch and Cb versions of the function, the main difference is that the size of the destination buffer is specified in each call. This provides the string safe functions with the ability to ensure that the destination buffer is not overrun. In addition, the functions return a status so that we can be sure to terminate function processing if an error occurs. (Continued from page 8) RtlUnicodeStringXxxCopyN, RtlUnicodeStringXxxCopyNEx RtlUnicodeStringXxxCopyStringN, RtlUnicodeStringXxxCopyStringNEx Building Your Code Example Let us assume for the moment that you need to write a function to generate the full name of a file from an input full directory path and the handle to a file. Furthermore, we will also assume that we will never see a long path name, because everyone must be like us and hate to have long file names. Thus the function that you may write to handle this could be as shown in Figure 1. If you analyze this code, I am sure that you can see a great many faults that could occur in this code. Most of them center around overrunning the dirname buffer since we forgot to look at the string lengths of the buffers we were concatenating from. A better solution to this function could be either Figure 2 or Figure 3 (P. 10), one illustrating the use of the In order to build your code correctly, you may want to know about the compile time variables that you can define to allow you to optimize how you use the string safe functions. STRSAFE_LIB If you want to use the string safe functions in library form then define STRSAFE_LIB before including "strsafe.h" in your code. In addition, you will need to insure that you link your code against "$(SDK_LIB_PATH)\strsafe.lib". Why do this? Well, instead of including the string safe routines that you use in your binary, this allows your driver to dynamically bind to the string safe functions when it loads, (Continued on page 10) wchar* GenerateFullPath(wchar* fulldirPath,HANDLE File) { static wchar dirname[100]; // assume you think all paths are small wchar* fileName = NULL; ASSERT(fulldirPath); ASSERT(File); fileName = GetFileName(File); strcpy(dirname,fulldirPath); strcat(dirname,L"\\"); strcat(dirname,fileName); // // // // Get the name of the input file copy the input dir name append a \ to the name concatenate the filename return dirname; // return the full path to the caller. } Figure 1 String Safe Functions CRT Functions Replaced StringCbCat, StringCbCatEx strcat,wcscat,lstrcat,strcat,StrCatBuff,_tcscat,_ftcscat StringCbCatN, StringCbCatNEx strncat,StrNCat StringCbCopy, StringCbCopyEx strcpy,wcscpy,lstrcpy,strcpy,_tcscpy,_ftcscpy StringCbCopyN, StringCbCopyNEx strncpy StringCbGets, StringCbGetsEx gets,_getws_getts StringCbPrintf, StringCbPrintFEx sprintf,swprintf,wsprintf,wnsprintf,_stprintf,_snprintf,_snwprintf, _sntprintf StringCbVPrintf, StringCbVPrintfEx vsprintf,vswprintf,wvsprintf,wvnsprintf,_vstprintf,_vsnprintf, _vsnwprintf, _vsntprintf StringCbLength strlen Table 2 Page 10 revision of the string safe functions will be compiled as part of your driver code (i.e., the implementations of the routines will be compiled as part of "strsafe.h"), and you do not need to link against strsafe.lib String Safe... STRSAFE_NO_DEPRECATE (Continued from page 9) hopefully allowing you to be running against the latest most improved implementations of these functions. This can be both good and bad. Example: #define STRSAFE_LIB #include <strsafe.h> Normally when you include "strsafe.h" all older functions (cruntime functions) that are replaced by "strsafe.h" defined functions are deprecated, i.e. you are given warnings that that the functions are not to be used and you are urged to use their string safe equivalents. If for some unknown reason you have to use one of these functions, you should define STRSAFE_NO_DEPRECATE. This definition will suppress the warnings and allow you to compile your driver. If you don't define STRSAFE_LIB in your code, the current wchar* GenerateFullPath(wchar* fulldirPath,HANDLE File) { static wchar dirname[MAX_PATH]; wchar* fileName = NULL; NTSTATUS status; ASSERT(fulldirPath); ASSERT(File); ASSERT(MAX_PATH <= STRSAFE_MAX_CCH); fileName = GetFileName(File); // Get the name of the input file status = RtlStringCchCopyW(dirname,MAX_PATH,fulldirPath); if(!NT_SUCCESS(status) { return NULL; } status = RtlStringCchCatW(dirname,MAX_PATH,L"\\"); if(!NT_SUCCESS(status) { return NULL; } status = RtlStringCchCatW(dirname,MAX_PATH,fileName); if(!NT_SUCCESS(status) { return NULL; } return dirname; // return the full path to the caller. } Figure 2 — Cch String Safe Usage wchar* GenerateFullPath(wchar* fulldirPath,HANDLE File) { static wchar dirname[MAX_PATH]; wchar* fileName = NULL; NTSTATUS status; ASSERT(fulldirPath); ASSERT(File); ASSERT(MAX_PATH <= STRSAFE_MAX_CCH); fileName = GetFileName(File); // Get the name of the input file status = RtlStringCbCopyW(dirname,MAX_PATH*sizeof(WCHAR),fulldirPath); if(!NT_SUCCESS(status) { return NULL; } status = RtlStringCbCatW(dirname,MAX_PATH*sizeof(WCHAR),L"\\"); if(!NT_SUCCESS(status) { return NULL; } status = RtlStringCbCatW(dirname,MAX_PATH*sizeof(WCHAR),fileName); if(!NT_SUCCESS(status) { return NULL; } return dirname; // return the full path to the caller. } Figure 3 — Cb String Safe Usage (Continued on page 11) Page 11 String Safe... Example: (Continued from page 10) Summary #define STRSAFE_NO_CCH_FUNCTIONS #include <strsafe.h> Example: #define STRSAFE_NO_DEPRECATE #include <strsafe.h> STRSAFE_NO_CB_FUNCTIONS If for some reason you want to limit your code to only use character count related string safe functions, then you should define STRSAFE_NO_CB_FUNCTIONS. This definition will then limit your code to the use of the RtlStringCchxxx functions. While it may seem like a hassle to learn a new set of functions to replace the old c-runtime functions that we have grown to love, it really is in your best interest to change. The string safe functions provided in "strsafe.h" provide you with a robust set of functions which will make your driver safer from buffer overruns and silly string mistakes that we all tend to make. Example: #define STRSAFE_NO_CB_FUNCTIONS #include <strsafe.h> STRSAFE_NO_CCH_FUNCTIONS Similarly, the STRSAFE_NO_CCH_FUNCTIONS define allows you to limit your code to only use byte count related string functions. Using this definition will then limit your code to use of the RtlStringCbxxx functions. Corporate, Onsite Training Save Money, Travel Hassles, Gain Customized Expert Instruction If you’re not aware of the value and benefit of bringing OSR to your location for seminars, we’re obviously not doing our job (blame Dan!). With tightened training budgets and/or travel restrictions combined with increased travel costs, OSR’s private, on-site training solutions can be your way to convince management that they can “have their cake and eat it too”. We can: Prepare and present a one-off, private, on-site seminar for your team to address a specific area of deficiency or to prepare them for an upcoming project Design and deliver a series of offerings with a roadmap catered to a new group of recent hires or within an existing group. Work with your internal training organization/HR department to offer monthly or quarterly seminars to your division or engineering departments company-wide. With any option, OSR’s seminar staff, in conjunction with the instructor, will work with you in advance to help craft a training solution that will maximize technical value and ensure you’re getting the most from your training budget. To take advantage of our expertise in Windows internals, and in instructional design, contact an OSR seminar consultant at +1.603.595.6500 or by email at [email protected]. Page 12 DPCs... (Continued from page 1) context for the callback, and a bit of control data: typedef struct _KDPC { UCHAR Type; UCHAR Importance; USHORT Number; LIST_ENTRY DpcListEntry; PKDEFERRED_ROUTINE DeferredRoutine; PVOID DeferredContext; PVOID SystemArgument1; PVOID SystemArgument2; __volatile PVOID DpcData; } KDPC, *PKDPC, *PRKDPC; You initialize a DPC Object with KeInitializeDpc and queue the DPC Object with KeInsertQueueDpc. Drivers that use DPCs to perform more extensive work than is appropriate for an Interrupt Service Routine typically use the DPC Object that's embedded in the Device Object, and cause this DPC Object to be queued by calling the function IoRequestDpc (which internally calls KeInsertQueueDpc). Once queued, at some point in the future your DPC routine is invoked from an arbitrary thread context at IRQL DISPATCH_LEVEL. With that basic info in hand, we can now cover the gory details of both the queuing and delivery mechanisms that are used for DPCs. That will lead us to discussing what options we have for controlling the behavior of DPCs and what impact those options have. DPC Queuing As mentioned previously, DPCs are queued (directly or indirectly) via the KeInsertQueueDpc DDI: NTKERNELAPI BOOLEAN KeInsertQueueDpc ( __inout PRKDPC Dpc, __in_opt PVOID SystemArgument1, __in_opt PVOID SystemArgument2 ); DPCs are actually queued to a particular processor, which is accomplished by linking the DPC Object into the DPC List that’s located in the Processor Control Block (PRCB) of the target processor. Determining the processor to which the DPC Object is queued is fairly easy for the O/S. By default, the DPC is queued to the processor from which KeInsertQueueDpc is called (the " cur r ent pr ocessor " ). However, a driver writer can indicate that a given processor be used for a particular DPC object, using the function KeSetTargetProcessorDpc. Viewing the DPC List on a particular processor is easy using WinDBG. While the DPC List is actually contained within the PRCB, the PRCB is an extension of the Processor Control Region (PCR). By viewing the PCR with the !pcr command we can see any DPCs currently on the queue for that processor: 0: kd> !pcr 0 KPCR for Processor 0 at ffdff000: Major 1 Minor 1 NtTib.ExceptionList: NtTib.StackBase: NtTib.StackLimit: NtTib.SubSystemTib: NtTib.Version: NtTib.UserPointer: NtTib.SelfTib: 8054f624 805504f0 8054d700 00000000 00000000 00000000 00000000 SelfPcr: Prcb: Irql: IRR: IDR: InterruptMode: IDT: GDT: TSS: ffdff000 ffdff120 00000000 00000000 ffffffff 00000000 8003f400 8003f000 80042000 CurrentThread: 8055ae40 NextThread: 81bc0a90 IdleThread: 8055ae40 DpcQueue: 0x8055b4a0 0x805015ae [Normal] nt!KiTimerExpiration 0x81b690a4 0xf9806990 [Normal] atapi!IdePortCompletionDpc 0x818a12cc 0xf96c5ee0 [Normal] NDIS!ndisMDpcX One aspect of DPCs to note is that once a DPC Object has been queued to a processor, subsequent attempts to queue the same DPC Object are ignored until the DPC Object has been dequeued (by Windows for execution of its callback). This is what the BOOLEAN return value of KeInsertQueueDpc indicates: TRUE means that Windows queued the DPC to the target processor and FALSE means that the DPC Object is already queued to some processor. This makes sense from a programming perspective, as the DPC data structure only has a single LIST_ENTRY field and thus can only appear on a single queue at a time. What About Priority? Where the DPC is placed on the target processor’s DPC List is an interesting question. Whether a DPC Object is inserted at the beggining or end of the target processor’s DPC List is one aspect of the priority feature of DPCs. You can set the importance of a given DPC Object by using the function KeSetImportanceDpc. This DDI lets you indicate that the DPC object is low, medium, or high importance. Also, in Vista and later you can set the importance to “medium high.” Low, medium, and medium high importance DPCs are placed at the end of the DPC queue, while high importance DPCs are placed at the front of the queue. You may ask yourself at this point, "then what's the difference between low, medium, and medium high?" We'll answer that question shortly. The DISPATCH_LEVEL Software Interrupt Once the DPC has been queued to the target processor, a DISPATCH_LEVEL software interrupt is typically generated on the processor. The choice of whether or not to request the DISPATCH_LEVEL software interrupt when the DPC Object is queued is largely based on four factors: the importance of the DPC, the target processor of the DPC, the depth of the DPC List on the target processor, and "drain rate" of the DPC List on the target processor. (Continued on page 13) Page 13 DPCs... If the target processor for the DPC Object is the current processor, the DISPATCH_LEVEL software interrupt is requested if the DPC Object is of any importance other than low. For low importance DPCs, the software interrupt is only requested if the O/S believes that the processor is not servicing DPCs fast enough, either because the DPC queue has become large or is not draining at a sufficiently fast rate. If either of those are true, the interrupt is requested even if the DPC is low importance. If the target processor for the DPC Object is not the current processor, the decision process is different. Because requesting an interrupt on the other processor will involve a costly Inter Processor Interrupt (IPI), the situations under which it is requested are restricted. Prior to Vista, the IPI request would only be made if the DPC was high importance or if the DPC queue on the target processor had become too deep. Vista added the medium high importance DPCs to the check and went one step further to cut down the number of IPIs by requiring the target processor to be idle for the DISPATCH_LEVEL software interrupt to be requested (See Table 1 for a high-level breakdown). DPC Delivery Once the DPC has been queued to the processor, at some point it must be dequeued and the callback executed. Remember that there were two scenarios that occurred after the DPC was queued to the processor, either the DISPATCH_LEVEL software interrupt was requested or it was not. Delivery from the Software Interrupt Service Routine To keep things relatively simple, we’ll restrict our discussion here to the case of queuing the DPC Object to the current processor. Let's start with the case in which the IRQL DISPATCH_LEVEL software interrupt was requested. At the time KeInsertQueueDpc was called, there are two situations the system could be in: The first would be running at an IRQL < DISPATCH_LEVEL, in which case the DISPATCH_LEVEL interrupt would be delivered immediately. The second case would be if the current processor is at IRQL >= DISPATCH_LEVEL, in which case the interrupt would remain pending until the IRQL was about to return to an IRQL < DISPATCH_LEVEL. In either case, once the service routine for the DISPATCH_LEVEL interrupt begins executing, it checks to see if any DPCs are queued to the current processor. If the DPC queue is not empty, Windows will loop and entirely drain the DPC List before returning from the service routine. Before draining the DPC List, Windows wants to ensure that it has a fresh execution stack for the DPC routines to run on. This will presumably cut down the incidents of stack overflows in the case where the current stack does not have much space remaining. Thus, every PRCB also contains a pointer to a previously allocated DPC stack that Windows switches to before calling any DPCs: 0: kd> dt nt!_KPRCB DpcStack +0x868 DpcStack : Ptr32 Void We can see evidence of the switch in the debugger if we set a breakpoint in a DPC routine. Here we chose a DPC from the ATAPI driver: 0: kd> bp atapi!IdePortCompletionDpc 0: kd> g Breakpoint 1 hit atapi!IdePortCompletionDpc: f9806990 8bff mov edi,edi 0: kd> k ChildEBP RetAddr f9dc7fcc 80544e5f atapi!IdePortCompletionDpc f9dc7ff4 805449cb nt!KiRetireDpcList+0x61 f9dc7ff8 f9a2b9e0 nt!KiDispatchInterrupt+0x2b WARNING: Frame IP not in any known module. Following frames may be wrong. 805449cb 00000000 0xf9a2b9e0 Notice the strange call stack - it seems to disappear after the call to KiDispatchInterrupt. The problem is that WinDBG has ceased to be able to unwind the stack due to the stack switch, and the call stack that we see here is the call stack for the DPC stack. If we try to match the EBP addresses shown with the stack limits of the current stack we will see the discrepancy: (Continued on page 14) DPC Importance Target Processor DPC Inserted At… DISPATCH_LEVEL Software Interrupt Generated? Low Current END NO Low Other than Current END Medium Current END Medium Other than Current END MediumHigh Current END MediumHigh Other than current END High Current HEAD High Other than current HEAD IPI Generated? NO YES NO YES YES (Vista: if target idle) Table 1 YES YES (Vista: if target idle) Page 14 DPCs... stack. Because the idle loop uses so little thread stack itself, there is not much use in going through the effort of swapping stacks in this case. (Continued from page 13) Conclusion 0: kd> !thread THREAD 81964770 Cid 028c.02b8 Teb: 7ffd8000 Win32Thread: e1873008 RUNNING on processor 0 IRP List: 8195b870: (0006,0190) Flags: 00000970 Mdl: 00000000 819128b0: (0006,0190) Flags: 00000970 Mdl: 00000000 Not impersonating DeviceMap e1001980 Owning Process 818d5978 Image: csrss.exe Attached Process N/A Image: N/A Wait Start TickCount 6779 Ticks: 0 Context Switch Count 4104 LargeStack UserTime 00:00:00.000 KernelTime 00:00:00.265 Start Address 0x75b67cd7 Stack Init f9a2c000 Current f9a2ba58 Base f9a2c000 Limit f9a29000 Call 0 Hopefully this cleared up a few misconceptions about DPCs and how they are handled by the system. Note that the EBP addresses do not fall within the base and limit of the current thread's stack. Using the techniques outlined in last issue's Debugging Techniques: Take One...Give One article (September-October 2008), you can actually get the original call stack of the interrupted thread back. This can be useful as it sometimes can provide key information as to what kicked off a chain of events on that processor. Once the O/S has switched stacks, it begins dequeuing DPC objects and then executing the call backs. Thus, while your DPC routine is executing, it is no longer on any DPC queue and may be queued again. Delivery from the Idle Thread But what about those low importance DPCs or targeted DPCs that didn't request the DISPATCH_LEVEL software interrupt? Who processes those? Well, there are actually two ways in which they'll be processed. Either another DPC will come along that will request the DISPATCH_LEVEL interrupt and the DPC will be picked up on the subsequent drain, or the idle loop will come along and notice that the DPC queue is not empty. Part of the idle loop's work is to check the DPC queue and determine if it is empty or not. If it finds that the queue is not empty, it begins draining the queue by dequeuing entries and calling the callbacks. We can see this in a different call stack but using the same DPC routine as the previous example: Breakpoint 1 hit atapi!IdePortCompletionDpc: f9806990 8bff mov edi,edi 0: kd> k ChildEBP RetAddr 80550428 80544e5f atapi!IdePortCompletionDpc 80550450 80544d44 nt!KiRetireDpcList+0x61 80550454 00000000 nt!KiIdleLoop+0x28 The difference here is that in this case the stack is not switched, thus the DPCs actually executed on the idle thread's Kernel Debugging for Windows You’ve seen our articles where we delve into analyses of various crash dumps or system hangs to determine root cause. Want to learn the tools and techniques yourself? Consider attendance at OSR’s Kernel Debugging for Windows seminar. This hands-on training not only provides fundamentals you need to debug Windows kernelmode software, but spends considerable time showing you the valued techniques that are used and espoused internally at OSR. The next offering of this limited-attendance seminar is to be held in Portland, Oregon from 6-10 April! Act soon, to save your seat! For more information, visit us at www.osr.com or call us at +1.603.595.6500, or email us at [email protected]. Page 15 is that filters are often written to target NTFS first and only once working against NTFS are they moved to other file system. Filtering... (Continued from page 7) environment and must be written to handle the ramifications of those interactions. The simplest way to handle these interactions is to simply ignore them – in other words, don’t get involved in the data flow through the system. That is definitely the simplest solution. Many filters must become involved in this in at least some fashion, however. Filters that are involved in I/O operations need to understand these interactions. Still, it is beyond the scope of this article to describe these complexities. The point, however, is that in order to build a robust file system filter driver, you really do need to understand the file system. Redirectors Do Not Behave Like Local File Systems Some filters can restrict themselves simply to a single file system (e.g,. NTFS) or perhaps to a class of file systems (physical file systems) but many filters must handle the network as well. Over the years, the pattern we have observed Sadly, this approach fails horribly when it comes to the network file systems. Filters that “work fine” on NTFS frequently exhibit serious problems when moved to the Windows redirector. Indeed, over the years, we’ve observed that it is often better to start with the network case and then move to NTFS – its generally a far less painful move than vice versa, particularly because project management often assumes that “once it works on NTFS we’re almost done.” Some of the issues we have seen when it comes to filtering network redirectors over the years include: Naming. Nothing in the local file system arena prepares you for the hideous complexity of naming in the network. Effectively, file names may be aliased due to hard links (which at least exist for physical file systems) but also due to overlapping shares not to mention special names sent by DFS to the redirector. Context. On a local file system, it is rather easy to track unique instances of a given stream (“stream” is Figure 1—A Complex Environment to Exist In (Continued on page 16) Page 16 Filtering... (Continued from page 15) the NTFS terminology. On FAT, there is only a single stream within a file, but in NTFS there can be many streams within a single file). This is typically done using the FsContext parameter of the file object. Legacy filters may do this directly (via a lookup table keyed from this value) or indirectly (via a “filter context” that is attached to a list within the FsContext structure). Mini-filters rely upon Filter Manager; Filter Manager in turn relies upon filter contexts. The Windows redirector, however, does not necessarily use the same context even for two file objects pointing to the same file. This works correctly for them, but it violates this basic assumption in many filter drivers. Further complicating this, the network file systems may coalesce file objects together – changing their FsContext values when it detects two instances of the same file. Filters, once again, must be able to handle this particular case. Relative open “issue”. IoCreateFileSpecifyDevice ObjectHint (in at least some still in-use versions) has an issue when performing a relative open over the Windows redirector. In our experience, it is necessary to always construct “fully qualified path names” and send these into this API – or any API (e.g., FltCreateFile and its progeny) that relies upon it. Let’s not lose sight of the fact that there are also two other network redirectors that ship with at least one version of Windows (“in the box”) – WebDAV (the http protocol for “distributed authoring and versioning”) and NFS (which is shipped as part of the Vista and Server 2008 distributions, although versions were previously available as “Services for Unix”). Maybe You Need to Support Systems Older Than Windows 7 As difficult as it is for those in Redmond to believe, there are still a few stragglers left using Windows versions prior to Windows 7 (please don’t miss the sarcasm, though the point is still valid). There are various reasons for this, but the biggest driver really is the cost associated with upgrading the systems. Particularly when those systems are performing their primary function properly, there is no compelling reason. People that do not need transactions, bit locker, resizable thumbnails, fancy graphical features and the like and instead are focused on executing custom software solutions, running embedded devices, etc. are very resistant to upgrading their systems. In spite of this resistance, they do expect their anti-virus products, quota managers, content control managers, backup components, encryption products, etc. to work on their version of Windows. Microsoft does not receive revenue from old versions of Windows, but those of us building filter drivers receive revenue from building products for those older versions. This creates a constant tension between the general development community (that needs support for any version that is still in use by their customer base) and the desires of Microsoft (which is to move the platform forward so their customers will buy an upgrade). The harsh reality is that we have a huge number of versions of Windows to support. Microsoft wants everyone to move to mini-filters (and has clearly stated they will enforce this at some point, which seems as if it will just force the legacy support to go “underground”). Each new platform requires additional resources to test and fix bugs – there are always changes in behavior, often for very specialized usage cases (transactions come to mind) that can directly impact on your own development (transactions matter to filters because filters see the “forward” operations but see no I/O if the transaction is aborted – even though the state of the underlying system changes). Testing is Difficult We can give you a basic list of the “tools of the trade” but the bottom line is that no matter how much testing you perform, you will never be able to cover every case. In all fairness, debugging a problem that manifests itself via an application – perhaps a common one like “Explorer” (common but still amazingly frustrating) or perhaps something far less common, like “Avid Newscutter Nitris DX” – is always going to be rather challenging to debug because it often requires that you determine why the application fails – you know it is related to something you are doing, but you don’t know what it is. Microsoft does not provide us with a conformance test. The closest thing we have (the ifskit tests) have mysterious failure modes and are often as inscrutable to understand as any failing application. Indeed, we generally do not investigate “SEV2” issues because we’ve found they generally are of the “oh, we don’t work the same way that NTFS does in this case” category. Another tool we often point out to people is the “FileTest” utility. It allows you to exercise uncommon operations like “open by file ID” that can be difficult to simulate with an offthe-shelf program, but need to work properly within your filter driver. I/O Stress can be useful for finding issues in your I/O handling paths. Driver Verifier is a must – if you aren’t using it during development and part of your testing, you aren’t doing a good job. However, you must also test without Driver Verifier enabled. We’ve even seen cases where Driver Verifier has tests that only trigger on single processor computers! At OSR, we have our own testing framework – it’s a scripting language that is built against the native API and allows us to trivially write scripts that can test the native windows API. If you restrict yourself to the Win32 API, your tests will definitely be deficient, since it is a subset of the functionality in the native API. Finally, don’t forget to test via the network – but this time, with the file SERVER running over your filter. Again, you will see different behavior. For example, the SL_INDEX_SPECIFIED option that is used for directory enumeration is difficult to trigger –but does show up with (Continued on page 17) Page 17 Filtering... some versions of the Windows file server software. Naturally, this is exercised when you access files over the network. Oh, and lest you missed this fact, you now (beginning with Server 2003) need to test between machines – loopback mode has been optimized out so that it bypasses the normal client/server model (allegedly there is a registry parameter to disable this functionality, but usually we find it easier to simply tell test organizations to use two computers, since that’s going to be the most common configuration “in the field”). Don’t Forget Plugfest For anyone working with file system filter drivers should always plan on attending the periodic 'Plugfest' that Microsoft sponsors to aid interoperability. While the opportunity to do direct developer-to-developer interop testing is invaluable, the contacts - both Microsoft and third party vendors - are often more valuable. The events are sponsored by the file systems filtering team at Microsoft and are done directly at the Microsoft main campus. These events are publicized in a variety of ways, including via OSR's well regarded NTFSD mailing list, a highly technical discussion group talking about the development of file systems and file system filter drivers for Windows." Conclusions File system filter drivers are the most complicated type of filter driver to write on Windows; deceptively, they span a very broad range, from “simplistic” (a surprising number of examples fall into this category) to “more complicated than a file system driver”. There are many reasons for this and we’ve tried to touch on some of them. But if you are building a file system filter driver because you think it will be “simpler” than a file system driver, you are likely to be unpleasantly surprised. If you can achieve your functionality without a filter driver, we would suggest doing it in that way. A real filter driver is truly a challenge to build. File Systems Development Kit For more than ten years, OSR’s File System Development Kit has been used to develop stable, highly functional, performant and commercially successful file system solutions in the Windows enterprise. Local, remote, embedded, pseudo, layered—whatever type of file system your project requires, the OSR FSDK has been put to the test. What more can you ask for but a hardened solution, that is maintained and fully-supported by industry-recognized experts? We provide a straight-forward interface for you to develop against, while managing the complex interactions with Windows. This means you can utilize your engineering resources to implement your product’s value-add, without having to worry about the myriad of edge cases that you don’t even know about. Want to know more? Check out the interface document available for the FSDK toolkit at www.osr.com. Call or email us with questions. Send your requirements for us to review under NDA. Remember we’re here to help — were not in the business of licensing one of our toolkits to someone with a, “good luck and have a nice day”. We are here to make our clients successful. If this technology and OSR’s reputation is something you think you can take advantage of, we look forward to hearing from you. Contact us at [email protected]. Page 18 How to Fetch... Checked Components for Vista/Server 2008 OSR would like to thank Mark Roddy for this contribution, originally posted to the OSR-hosted NTDEV mailing list. Just because this was such a royal PITA for what used to be such a trivial task, I thought I would share how I wasted an entire day with the rest of you, and perhaps spare some unfortunate the grief I went through. Task: obtain the checked version of an inbox driver for Vista or later OS release in order to install that driver for debugging purposes. Estimated time to complete: one to two hours, based on prior experience with other OS platforms. Most of that time would be spent downloading an OS image if a DVD or CD were not available. and installed, you now have to puzzle over which three little files Don was referring to. Read the awful WAIK docs. Zero in on imagex and the clutter of command line options that go with it. That would be one file of the requisite three. Then infer that wimfltr.sys and wimfltr.inf are the other two useful files. Note that the WAIK does not contain any reference I can find regarding how one ought to install wimfltr.sys, although it does note that it is required every now and then. 5. Decide that imagex rivals bcdedit in command line option fatigue. Google how other people are actually using this thing. End up here: http://www.windows-now.com/blogs/robert/ archive/2007/11/04/mounting-wim-images-from-windowsexplorer.aspx and from there here: http://www.autoitscript.com/gimagex/. 6. Download gimagex from that last link. Actual time to complete: approximately eight hours and one headache. 7. Install wimfltr (right click on the inf file, select install.) No need to reboot! 1. Search MSDN for a complete checked distribution of the OS (Vista SP1 in this case). MSDN, which had a frightfully bad archive catalog system, now has managed to reimplement that as a hideously and frightfully bad catalog system. As far as I can tell, without an MSDN subscription you cannot find a post-RTM version of the checked distribution legitimately. Note that if you just want the hal and kernel, they are in the WDK. 8. Use gimagex to mount \sources\install.wim from the checked debug build. 2. Download the image - approximately 2.5GB. Take a nap. Run some errands. Now all I have to do is remember what it was I was doing to begin with that made me decide that using a debug inbox driver would be a good idea. 3. Mount the image either by burning it to DVD or using any of the useful image mounting programs out there. Spend (waste) quite a while searching the image for drivers and come up with nothing. Google this puzzle and discover of course that Don Burn has been here before and noted that now you need to download the WAIK: Microsoft definitely changed things. What you need to do is download the Windows Automated Installation Kit at http:// www.microsoft.com/downloads/details.aspx? familyid=C7D4BC6D-15F3-4284-9123679830D629F2&displaylang=en. This provides a file system that will allow you to open the files on the DVD's and extract the individual files you need. Unfortunately the kit is almost 1GB and you need three small files from it. http://www.tech-archive.net/Archive/ Development/microsoft.public.win32.programmer. kernel/2007-09/msg00073.html. 4. Download the WAIK - another hour of my life lost. I did have a nice camembert on rye sandwich. Once downloaded 9. Browse around like you did back in the good old XP/W2K3 days and find the driver images you were looking for to begin with and copy them somewhere safe. Heck, while you are there, copy all the drivers from the image to someplace reasonable. Page 19 Who Was at the DDC? Well, We Were, But... N fall? othing like hanging around in building 33 on the Microsoft Redmond campus waiting for...um, the sky to Anyway, this is where we found ourselves during a break from presentations at the Windows Driver Development Conference (DDC) when we ran into a few colleagues from the driver development community. Fortunately, someone even had a camera to capture the Kodak moment! To the right (left to right) you’ll see: OSR’s Peter Viscarola; DDK MVP Maxim Shatskih; Jake Oshins, Microsoft Hyper-V I/O Architect. Below, Peter and Jake are joined (left to right) by DDK MVP Martin O’Brien; OSR’s Scott Noone; OSR’s Mark Cariddi. A hearty thanks to Maxim for the pics, and to these folks and others who hung with us for some couch time during the conference. Page 20 New OSR Seminar Schedule! Seminar Developing File System Mini-Filters (Lab) Writing WDF Drivers (Lab) Kernel Debugging (Lab) Writing WDM Drivers (Lab) Developing File Systems Dates Location 23-27 February Boston, MA 30 March—3 April Portland, OR 6-10 April Portland, OR 27 April—1 May Boston, MA 4-7 May Boston, MA Course outlines, pricing, and how to register at: www.osr.com/schedule The NT Insider™ is a subscription-based publication OSR Open Systems Resources, Inc. 105 State Route 101A, Suite 19 Amherst, New Hampshire 03031 USA (603)595-6500 ♦ Fax (603)595-6503 RETURN SERVICE REQUESTED PRESORTED FIRST CLASS MAIL U.S. POSTAGE PAID PERMIT # 456 MANCHESTER, NH First Class