read fails with EINVAL for 4k sector size and device_block_size_fd returns zero incase of files
While running compaq-test from tests in cryptsetup fails on 4k sector size .
To reproduce:
cd tests
bzip2 -cd compatv10image.img.bz2 > luks-test-v10
echo compatkey | cryptsetup luksOpen luks-test-v10 dummy
./test.sh
IO error while decrypting keyslot.
From strace:
strace -o out cryptsetup luksOpen luks-test-v10 dummy
Enter passphrase for luks-test-v10:
IO error while decrypting keyslot.
Exact failure hapens here:
open("luks-test-v10", O_RDONLY|O_SYNC|O_DIRECT) = 8
lseek(8, 1024, SEEK_SET) = 1024
fstatfs(8, {f_type="EXT2_SUPER_MAGIC", f_bsize=4096, f_blocks=5771455, f_bfree=3232851, f_bavail=2938013, f_files=1474560, f_ffree=1367156, f_fsid={-986750135, -1530440040}, f_namelen=255, f_frsize=4096}) = 0
fstat(8, {st_mode=S_IFREG|0644, st_size=10240000, ...}) = 0
--
read(8, 0x95968000, 61440) = -1 EINVAL (Invalid argument)
The file is opened in O_DIRECT mode which succeeds, but following read fails with EINVAL. Similar kind of issue was reported in cryptsetup and there is fix in https://gitlab.com/cryptsetup/cryptsetup/issues/247 and commit: https://gitlab.com/cryptsetup/cryptsetup/commit/0bc437d92c30945991881c8b8ca245a016fc1236
Even with this fix, it fails here. Basically this fix tries to read first sector after opening file in O_DIRECT mode and verify if O_DIRECT works.
In this commit, in case of files, in the code for returning block size ( device_block_size_fd in lib/utils_device.c ) , its not returning blocksize crrectly. Always it returns zero in case of files and device_read_test never gets executed.
Modified code to return correct block size for files.
Even after making this modification, compat-test fails for luks-test-v10.
code which fails:
if (lseek(devfd, sector * SECTOR_SIZE, SEEK_SET) == -1 || read_blockwise(devfd, bsize, dst, dstLength) == -1)
Here sector * SECTOR_SIZE is 1024 in case of file "luks-test-v10". Because value of sector is 2 ( which is the “Key material offset” for this file) .
file luks-test-v10
luks-test-v10: LUKS encrypted file, ver 1 [aes, cbc-plain, sha1] UUID: e0d6124b-f9b7-4592-8c27-5adaddb7f1a4
cryptsetup luksDump tests/luks-test-v10 |grep "Key material offset"
Key material offset: 2
And SECTOR_SIZE is always 512.
lseek to 1024 followed by read fails with EINVAL incase of 4k sector size disk. The device_read_test ( in lib/utils_device.c) tries to read first sector after opening file in O_DIRECT mode which works here, but failure happens with lseek followed by read.