2.6 Accessing File Information Securely

2.6.1 Problem

You need to access information about a file, such as its size or last modification date. In doing so, you want to avoid the possibility of race conditions.

2.6.2 Solution

Use a secure directory, as described in Recipe 2.4. Alternatively, open the file and query the needed information using the file handle. Do not use functions that operate on the name of the file, especially if multiple queries are required for the same file or if you intend to open it based on the information obtained from queries. Operating on filenames introduces the possibility of race conditions because filenames can change between calls.

On Unix, use the fstat( ) function instead of the stat( ) function. Both functions return the same information, but fstat( ) uses an open file descriptor while stat( ) uses a filename. Doing so removes the possibility of a race condition, because the file to which the file descriptor points can never change unless you reopen the file descriptor. When operating on just the filename, there is no guarantee that the underlying file pointed to by the filename remains the same after the call to stat( ).

On Windows, use the function GetFileInformationByHandle( ) instead of functions like FindFirstFile( ) or FindFirstFileEx( ). As with fstat( ) versus stat( ) on Unix (which are also available on Windows if you're using the C runtime API), the primary difference between these functions is that one uses a file handle while the others use filenames. If the only information you need is the size of the file, you can use GetFileSize( ) instead of GetFileInformationByHandle( ).

2.6.3 Discussion

Accessing file information using filenames can lead to race conditions, particularly if multiple queries are necessary or if you intend to open the file depending on information previously obtained. In particular, if symbolic links are involved, an attacker could potentially change the file to which the link points between queries or between the time information is queried and the time the file is actually opened. This type of race condition, known as a Time of Check, Time of Use (TOCTOU) race condition, was also discussed in Recipe 2.3.

In most cases, when you need information about a file, such as its size, you also have some intention of opening the file and using it in some way. For example, if you're checking to see whether a file exists before trying to create it, you might think to use stat( ) or FindFirstFile( ) first, and if the function fails with an error indicating the file does not exist, create the file with creat( ) or CreateFile( ). A better solution is to use open( ) with the O_CREAT and O_EXCL flags, or to use CreateFile( ) with CREATE_NEW specified as the creation disposition.

2.6.4 See Also

Recipe 2.3