cryptomator / cryptofs

Java Filesystem Provider with integrated encryption
GNU Affero General Public License v3.0
94 stars 35 forks source link

Flushing ChunkCache might write incomplete data #173

Closed infeo closed 1 year ago

infeo commented 1 year ago

When writing to a file channel, for performance reasons cryptofs differs writing on the condition "Does the content to be written fits exaclty in a chunk?" https://github.com/cryptomator/cryptofs/blob/ec3871dd4556af723fabf37a1be732b1fe576546/src/main/java/org/cryptomator/cryptofs/ch/CleartextFileChannel.java#L153-L159

If the condition is true, we directly replace the data in the cache: https://github.com/cryptomator/cryptofs/blob/ec3871dd4556af723fabf37a1be732b1fe576546/src/main/java/org/cryptomator/cryptofs/fh/ChunkCache.java#L82-L100

Also here a case distinction is made: Is the Chunk not present? On false, we overwrite the data of the existing chunk by are using JDKs [ByteBuffer::duplicate](https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/nio/Buffer.html#duplicate()) (getting an independet positon and limit.) and placing the data in the duplicate.

But this approach has the problem, that the chunks data limit is not adjusted! Hence, directly flushing the cache afterwards, this chunk contents will only be saved to the outdated limit before the write, leading to invalid ciphertext.

overheadhunter commented 1 year ago

For the record, here is a visualization of what happens in the chunk cache:

// write 1.5 chunks of data:
|xxxx|xx--|

// write 2.5 chunks of data at same pos
|xxxx|xxxx|xx--|

chunks[1] is still cached from the first write, however as it was the EOF chunk, its limit was set to 1/2 of its capacity.

Due to the mentioned „full chunk update“ mechanism, while its bytes were correctly updated during the second write, the limit has not been updated. It still behaves as if it was the last chunk.