Deleting a directory under Windows in a race-free manner? - winapi

http://code.google.com/p/guava-libraries/issues/detail?id=365 discusses the potential race-conditions that may occur while deleting a directory recursively.
According to http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7148952 this can be implemented in a race-free manner under Linux using openat(). Is there an equivalent mechanism under Windows?

A key difference between Windows filesystem behavior and linux filesystem behavior is locking and reference counting.
In Windows if a process has a file open, then that file and the path leading to that file are protected.
So, if somebody has "C:\a\b\c\d\file.txt" open, then nobody is allowed to rename or delete any part of the path "C:\a\b\c\d\file.txt".
The linux model is much different, any part of that path can be changed and even the file can be deleted. The process holding the handle to "file.txt" still has a reference, and the file wouldn't be removed from the filesystem until all handles are closed.
The Win32 API doesn't expose a direct way to hold a handle to a directory (though, there are APIs for this - see the "Zw" functions, FindFirstFile may I'm not sure, the backup APIs, etc) - but your process "current directory" does hold a handle for that directory.
Thus, you can get "openat" behavior by changing your working directory and then opening the file directly. Better would be to use something like ZwCreateFile() to open a handle to the directory - since the "current dir" is process global.
Search Stackoverflow and Microsoft.com for ZwCreateFile information.

Related

On Windows/NTFS can a symbolic link be moved to another computer?

For the purposes of a security test involving Windows servers, I would like to attempt uploading a Symbolic link to a Windows web application. However, based on the information officially available, it is unclear whether Windows hard links (Which I suppose are the same as NTFS junctions) exist as a file that can be copied from the hard disk the same way it does on Linux. It's vague, but I get the sense that NTFS junctions are some other kind of file system artifacts which is different than "regular" files - I can't find the documentation to confirm or deny this. I.E NTFS I want to know if NTFS supports the direct manipulation of the symlink record such that I could move the symlink to a different computer.
I am aware that Windows softlink files (.lnk) are not limited in this way, but they do not suit the purposes of the test.
My Aim is to copy a symlink off of a virtual machine, and then upload it to the server which I am testing.
Is this possible? (I am under the impression it is not.) From what I have seen absolutely every program on Windows would regard the hardlink as the destination file. Is there a way around this, perhaps by using a special editor to temporarily corrupt the file? If the symlink exists as a normal file on the file system can the symlink be altered so it can moved to a non-Windows OS for further use?
Let me know if this would be a better question for server fault. Since this is not directly about security, and is more of mundane technical problem in the service of a security exercise, I don't think it would fit on Stack Exchange security.
It's hard to provide a very direct answer. I work on a backup/repair/imaging project, and I copy whole disk images to a server via a web service - so, it's possible to do what you want, but there's a lot to consider.
Hardlinks
It is generally assumed that hardlinks cannot be distinguished from each other, however, there is a subtle difference between linked files and their "original" file. That difference is that queries to the $MFT (using USN-related arguments on the winapi function DeviceIOControl) will only return one of the files. This may be considered the original file. You can then call the winapi function NtQueryInformationFile to enumerate the hard links.
Symlinks and junctions are different animals...
You can know that a folder is a junction or a symlink, by getting the attributes from it. There's a ReparsePoint flag in the attributes if it's a junction or a symlink. BTW - the difference between junctions and symlinks is that the junction is a redirect to another location on the same volume, while a symlink is a redirect to an off-volume location. The redirect target is always another folder either way.
What's interesting is that both symlinks and junctions look and act like folders, while they are really files containing redirect information. When you open 'em, NTFS will normally look at the redirect, and open the redirect target. NTFS checks the permissions at the redirect target, so as an attack, this might not be a robust strategy.
When opening a junction/symlink, you can add a flag FILE_FLAG_OPEN_REPARSE_POINT. When you do this, NTFS does not perform the redirect, but opens the content, which is actually redirect information, and assuming you know the format of that information, it is possible to reconstruct the junction/symlink at the server. Note that the redirect may point to a location that may not exist, or may exist only temporarily. This is expected as some network resources may not always be available.
So, in short, it's possible to copy a junction or a symlink...while copying a hard link nominally means copying the file...with the foregoing subtleties in mind. You can create a hard link manually, too, as long as the target file exists.
With hardlinks, there's one interesting kink in the NTFS security picture. If a user has access to a file, and you create a hardlink to that file in a folder the user doesn't have access to, the user can still open that file using the path to the hard link. This is because the link and the original file are both pointing to the same file (and security info) on disk. Permissions changed on any of the links affect all the links. Without knowing this, you can inadvertently wreak havoc on a file system :-)
I know this is a bit helter-skelter, so let me summarize this way:
NTFS directory entries can be folders or files. Hardlinks are directory entries that all point to one file. Symlinks and junctions are really files that act like folders for most practical purposes (until you know how to get at the redirect info as described above).
AFAIR, NTFS (directory) junctions are actually symbolic links. The juctnion is implemented as a special file attribute called repars point that contains the link target.
Hardlinks, on the other hand, are implemented as direct references to the base MFT record of the target file and are stored as regular entries inside directory tree. You actually cannot distinguish a hardlink from the "original" file (every file and directory actually has at least one hardlink since it is contained somewhere within the directory tree).
If you wish to copy a symbolic link itself, you need to know that it is a symbolic link and extract the information about its target. File operations (except deletion and, probably, renamng) are redirected to the link target. So, you can, in general, copy a symbolic link by creating its exact copy in the destination area.
The actual question is, whether the interface you are using to perform the copy operation allows you to create symbolic links on the target.

Why does an open DLL Handle not protect file from being moved?

I just had a surprising bug where a DLL file that was loaded using the LoadLibrary API call was renamed while being loaded. Apparently, having an open DLL handle on a file does not prevent that file from being renamed, or even moved to a different path. It is however protected from deletion and being moved to a different disk. The program using the DLL continues to work fine if this happens. ProcessExplorer shows that the path of the DLL handle updates accordingly.
This behavior is different from ordinary file handles in Windows. For example, when keeping an open std::ifstream to the same DLL, renaming is no longer allowed by the operating system. I find this behavior quite surprising and was wondering if anyone could give an explanation for it? In particular I'd be interested in the rationale for allowing this, as I'd imagine the tracking of the file on disk to be more difficult than just locking it in place. So the OS probably has to actively support this feature, which means there has to be a use case for it?
It is not a bug. LoadLibrary uses File Mapping to access a file. While you have a mapped section to a file it cannot be deleted (or moved to another disk). It seems that LoadLibrary closes a file handle (it's not needed) and uses only a handle to the mapped section so you can freely rename the file but cannot delete it.
On the other hand std::ifstream uses a file handle to access a file. And it doesn't set FILE_SHARE_DELETE share access that is required for rename and delete operations.
Actually there is no special tracking of a file on the disk. A file handle points to the file and that's all. After you have opened a file and got its handle the file can be renamed or even deleted and you still have an access to that file (a limited access if the file has been deleted, but you can undelete the file and have a full access).

Invisible hardlink

I have a small application that displays the contents of a log file, somewhat transmogrified for readability. As the log file gets rewritten occasionally and Windows file system semantics prohibit deletion of open files, I create a hardlink to the file.
Obviously, this needs to happen on the same file system as the original file -- at present, I create the harddisk in the same directory, which I believe can be reasonably assumed to fulfill this requirement; the result is that a temporary file shows up in the directory listing where the user just clicked to open the file, which is ugly.
Is there a way to create a hardlink so that it does not show up (the customer where the program is used has several junctions in their directory tree, so it cannot be assumed that a specific directory is on the same filesystem), or is there a better method to read a file that another process may want to delete and rewrite (e.g. by catching their access and closing the file before letting the other process's access go through), so the program can be used on archived (readonly) log files without modification?
No
It won't help if you could. Sharing spans links.
Use the solution posed by Hans Passant as a comment.

How to get a process exclusive lock on a folder in Windows?

Is it possible to lock a directory in Windows so as to ensure that no other process is reading or modifying files inside the directory for the duration of the lock, while at the same time allowing the process with the lock to modify and move files and directory itself freely?
This is not a real answer, but as a workaround:
Move the directory to a subdirectory specific to your application, which is on the same volume.
Advantages:
Prevents users and other programs from modifying the file at the old location, as the files will no longer be there
Importantly, will fail if a process already has a file open within that directory, thus ensuring that the "acquired" lock is indeed "exclusive"
Disadvantages:
It's a hack
The software will need to be adapted to work with the directory at a different path than where it was initially
Users and programs attempting to access the files will encounter unusual behavior or errors ("Path not found" instead of "Access denied")
Does not protect against programs that may poke into your application-specific subdirectory
Will leave the directory "locked" (moved to a location the user probably can't find) if your program crashes while the "lock" is "held"

Renaming A Running Process' File Image On Windows

I have a Windows service application on Vista SP1 and I've found that users are renaming its executable file (while it's running) and then rebooting, thus causing it to fail to start on next bootup because the service manager can no longer find the exe file since it's been renamed.
I seem to recall that with older versions of Windows you couldn't do this because the OS placed a lock on the file. Even with Vista SP1 I still cannot copy over the existing file when it's running - Windows reports that the file is in use - makes sense. So why should I be allowed to rename it? What happens if Windows needs to page in a new code page from the exe but the file has been renamed since it was started? I ran Process Monitor while renaming the exe file, etc, but Process Mon didn't report anything strange and just logged changing the filename like any other file.
Does anyone know what's going on here behind the scenes? It's seem counter intuitive that Windows would allow a running process' filename (or its dependent DLLs) to be changed. What am I missing here?
your concept is wrong ... the filename is not the center of the file-io universe ... the handle to the open file is. the file is not moved to a different section of disk when you rename it, it's still in the same place and the part of the disk the internal data structure for the open file is still pointing to the same place. bottom line is that your observations are correct. you can rename a running program without causing problems. you can create a new file with the same name as the running program once you've renamed it. this is actually useful behavior if you want to update software while the software is running.
As long as the file is still there, Windows can still read from it - it's the underlying file that matters, not its name.
I can happily rename running executables on my XP machine.
The OS keeps an open handle to the .exe file,. Renaming the file simply changes some filesystem metadata about the file, without invalidating open handles. So when the OS goes to page in more code, it just uses the file handle it already has open.
Replacing the file (writing over its contents) is another matter entirely, and I'm guessing the OS opens with the FILE_SHARE_WRITE flag unset, so no other processes can write to the .exe file.
Might be a stupid question but, why do users have access to rename the file if they are not suppose to rename the file? But yeah, it's allowed because, as the good answers point out, the open handle to the file isn't lost until the application exits. And there are some uses for it as well, even though I'm not convinced updating an application by renaming its file is a good practice.
You might consider having your service listen to changes to the directory that your service is installed in. If it detects a rename, then it could rename itself back to what it's supposed to be.
There are two aspects to the notion of file here:
The data on the disk - that's the actual file.
The file-name (could be several or none) which you can give that data - called directory entries.
What you are renaming is the directory entry, which still references the same data. Windows doesn't care about your doing so, as it still can access the data when it needs to. The running process is mapped to the data, not the name.

Resources