Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why accessing ReadFileEx's input buffer prematurely can cause data corruption?

ReadFileEx's documentation says:

Accessing the input buffer while a read operation is using the buffer may lead to corruption of the data read into that buffer. Applications must not read from, write to, reallocate, or free the input buffer that a read operation is using until the read operation completes.

This is the first time I've ever heard of reading data causing corruption.
So my question is, why does that happen? How can a read operation possibly cause data corruption?
What's going on underneath that causes this?

Update:

I noticed an interesting sentence on ReadFile's page:

The ReadFile function may fail with ERROR_NOT_ENOUGH_QUOTA, which means the calling process's buffer could not be page-locked.

Maybe this is related to the answer?

like image 219
user541686 Avatar asked Oct 22 '22 16:10

user541686


2 Answers

I'm not really sure so I'm pretty open to comments but I guess:

ReadFileEx is implemented to use NtReadFile (more or less it's just a thin wrapper around it). NtReadFile does a lot of stuff but it uses IoBuildAsynchronousFsdRequest (or IoBuildSynchronousFsdRequest) to perform its task. From this article we know that:

If the target device object is set up do direct i/o (DO_DIRECT_IO), then IoBuildAsynchronousFsdRequest creates an MDL to describe the buffer and locks the pages.

(emphasis is mine)

Then I guess they call MmProbeAndLockPages with IoWriteAccess, this is done by the driver in kernel mode then the user supplied buffer (in user mode) can't even be accessed for read.

I don't know what will happen if you do it, probably a SEH exception will be thrown and your code will fail.

EDIT
As pointed out in the edited question even the ReadFile function forbids the user to read from the buffer until operation has been completed and it may returns ERROR_NOT_ENOUGH_QUOTA:

The ReadFile function may fail with ERROR_NOT_ENOUGH_QUOTA, which means the calling process's buffer could not be page-locked.

At least this makes clear that ReadFile (where the buffer isn't provided by the user) will allocate a page and it'll lock it (ok it has been said in the article I linked too...). It remains to understand if the corruption (if any, about this I strongly agree with @David) can occur with user defined buffer too (where a lock on the page, as pointed out by @Ben, most of times is impossible).

I don't think it uses page faults to detect buffer overruns simply because it knows the required amount of data before the call then it can allocate it once.

So why data can be corrupted? After all everything here can due to an error but not to data corruption. This is a big guess but there was a known issue about MmProbeAndLockPages:

This issue occurs because of a race condition in the Memory Manager. When a driver calls the MmProbeAndLockPages routine, this routine may read some data that is being modified by another thread. Therefore, data corruption occurs. Depending on how the corrupted data is used, the application or the system may crash.

It's hard to say if this issue has been resolved at very low level or if can still exploit if application does something weird...

like image 200
Adriano Repetti Avatar answered Oct 27 '22 09:10

Adriano Repetti


Most likely, the corruption when you read from the I/O buffer results from the race condition -- the buffer may be partially filled in when you read from it, and the order in which it is filled in is unspecified. In addition, Windows could store anything in there during the time it owns the buffer -- you aren't guaranteed to see either the prior content or the data from the file.

What you can be sure of is that it isn't related to access violations when reading from the buffer, because it's perfectly legal to continue accessing other data in the same page. Only the buffer itself is forbidden to your use. Now, when the file is open for direct unbuffered I/O (FILE_FLAG_NO_BUFFERING), and the volume sector size is a multiple of the memory page size, then, the buffer is required to correspond to a sequence of complete pages, so the kernel has more freedom at that point. But that's a very particular set of conditions, and it's rare for the sector size to exceed the memory page size.

like image 39
Ben Voigt Avatar answered Oct 27 '22 09:10

Ben Voigt