Discs must be sized in multiples of 512 bytes or odd things happen

In #36 some of the odd errors were due to seeks beyond the end of the
disc.  This was because the disc was "specially crafted" to be 25GB + 1
byte, which doesn't fit into the normal 512 byte sectors expected of a
disc.  This lead to reads going beyond the end of the disc etc.

If a similarly evil disc is used with `losetup`, it just ignores the
last bytes of the disc that don't fit into 512 chunks.  This is what
that patch does, logging an error at the same time.
This commit is contained in:
Patrick J Cherry
2018-02-08 16:31:28 +00:00
parent 1672b4b88b
commit 347b7978e4
3 changed files with 32 additions and 0 deletions

View File

@@ -97,6 +97,15 @@ int open_and_mmap(const char* filename, int* out_fd, uint64_t *out_size, void **
warn("lseek64() failed");
return size;
}
/* If discs are not in multiples of 512, then odd things happen,
* resulting in reads/writes past the ends of files.
*/
if ( size != (size & (~0x1ff))) {
warn("file does not fit into 512-byte sectors; the end of the file will be ignored.");
size = size & (~0x1ff);
}
if (out_size) {
*out_size = size;
}

View File

@@ -710,6 +710,15 @@ void serve_init_allocation_map(struct server* params)
FATAL_IF_NEGATIVE(fd, "Couldn't open %s", params->filename );
size = lseek64( fd, 0, SEEK_END );
/* If discs are not in multiples of 512, then odd things happen,
* resulting in reads/writes past the ends of files.
*/
if ( size != (size & ~0x1ff)) {
warn("file does not fit into 512-byte sectors; the end of the file will be ignored.");
size &= ~0x1ff;
}
params->size = size;
FATAL_IF_NEGATIVE( size, "Couldn't find size of %s",
params->filename );

View File

@@ -195,4 +195,18 @@ class TestServeMode < Test::Unit::TestCase
assert_equal 6, op.first[3], 'msync called with incorrect flags'
end
def test_odd_size_discs_are_truncated_to_nearest_512
# This should get rounded down to 1024
@env.blocksize = 1024 + 511
@env.writefile1('0')
@env.serve1
client = FlexNBD::FakeSource.new(@env.ip, @env.port1, 'Connecting to server failed')
begin
result = client.read_hello
assert_equal 'NBDMAGIC', result[:passwd]
assert_equal 0x00420281861253, result[:magic]
assert_equal 1024, result[:size]
client.close
end
end
end