kernel: Bounds-check the parameters passed to file_cache_read().

cache_io() did some bounds checking, but for uncached reads it was
entirely on the filesystem. Now we are more consistent: do all the
bounds checking for reads in the file cache, and do all bounds
checking for writes in the filesystems.

This makes sense as nearly all file systems were doing the exact
same logic for read() but of course all have different logic
for write(), due to block allocation, etc.

This potentially fixes #14993.

Change-Id: Iaf3e549001344cf375c7b8de549fc169d77bdbb2
Reviewed-on: https://review.haiku-os.org/c/1420
Reviewed-by: waddlesplash <waddlesplash@gmail.com>
This commit is contained in:
Augustin Cavalier 2019-04-29 14:16:27 -04:00 committed by waddlesplash
parent 1e4109cdb4
commit 728b515e1c

View File

@ -707,30 +707,15 @@ cache_io(void* _cacheRef, void* cookie, off_t offset, addr_t buffer,
file_cache_ref* ref = (file_cache_ref*)_cacheRef;
VMCache* cache = ref->cache;
off_t fileSize = cache->virtual_end;
bool useBuffer = buffer != 0;
TRACE(("cache_io(ref = %p, offset = %Ld, buffer = %p, size = %lu, %s)\n",
ref, offset, (void*)buffer, *_size, doWrite ? "write" : "read"));
// out of bounds access?
if (offset >= fileSize || offset < 0) {
*_size = 0;
return B_OK;
}
int32 pageOffset = offset & (B_PAGE_SIZE - 1);
size_t size = *_size;
offset -= pageOffset;
if ((off_t)(offset + pageOffset + size) > fileSize) {
// adapt size to be within the file's offsets
size = fileSize - pageOffset - offset;
*_size = size;
}
if (size == 0)
return B_OK;
// "offset" and "lastOffset" are always aligned to B_PAGE_SIZE,
// the "last*" variables always point to the end of the last
// satisfied request part
@ -1287,6 +1272,17 @@ file_cache_read(void* _cacheRef, void* cookie, off_t offset, void* buffer,
TRACE(("file_cache_read(ref = %p, offset = %Ld, buffer = %p, size = %lu)\n",
ref, offset, buffer, *_size));
// Bounds checking. We do this here so it applies to uncached I/O.
if (offset < 0)
return B_BAD_VALUE;
const off_t fileSize = ref->cache->virtual_end;
if (offset >= fileSize || *_size == 0) {
*_size = 0;
return B_OK;
}
if ((off_t)(offset + *_size) > fileSize)
*_size = fileSize - offset;
if (ref->disabled_count > 0) {
// Caching is disabled -- read directly from the file.
generic_io_vec vec;
@ -1308,6 +1304,10 @@ file_cache_write(void* _cacheRef, void* cookie, off_t offset,
{
file_cache_ref* ref = (file_cache_ref*)_cacheRef;
// We don't do bounds checking here, as we are relying on the
// file system which called us to already have done that and made
// adjustments as necessary, unlike in read().
if (ref->disabled_count > 0) {
// Caching is disabled -- write directly to the file.