diff --git a/debian/changelog b/debian/changelog index f08dc61..bfb4b83 100644 --- a/debian/changelog +++ b/debian/changelog @@ -15,6 +15,7 @@ flexnbd (0.2.0) UNRELEASED; urgency=medium * Proxy passes all NBD protocol errors through to the client instead of disconnecting and retrying (#36, !40) * Fix struct types in readwrite.c (#35, !41) + * Ignore ends of discs that stray outside of 512-byte sector sizes (!42). -- James Carter Thu, 11 Jan 2018 10:05:35 +0000 diff --git a/src/common/ioutil.c b/src/common/ioutil.c index 4c1a4bd..dfa47df 100644 --- a/src/common/ioutil.c +++ b/src/common/ioutil.c @@ -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 &= ~0x1ff; + } + if (out_size) { *out_size = size; } diff --git a/src/server/serve.c b/src/server/serve.c index d88e9f4..3a86c3a 100644 --- a/src/server/serve.c +++ b/src/server/serve.c @@ -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 ); diff --git a/tests/acceptance/test_serve_mode.rb b/tests/acceptance/test_serve_mode.rb index 4f9a77e..2299584 100644 --- a/tests/acceptance/test_serve_mode.rb +++ b/tests/acceptance/test_serve_mode.rb @@ -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