Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decryption buffer #2616

Merged
merged 4 commits into from
May 17, 2017
Merged

Decryption buffer #2616

merged 4 commits into from
May 17, 2017

Conversation

ironage
Copy link
Contributor

@ironage ironage commented May 17, 2017

The openssl implementation of AES_cbc_encrypt seems to use the destination as scratch and must make multiple iterations on a block before the decrypted result is produced. If we have multiple readers looking at the same mapping and a writer which updates that page in the file (at a later memory location) then one reader will find that the page is out of date and decrypt from the file again. This will work for the reader triggering the decryption, but the other reader that is using the same memory concurrently will have a chance to read the partially decrypted data.

The fix is to decrypt to a temporary buffer and copy the fully decrypted data afterwards. The memory is then guaranteed to be the same for any concurrent readers.

This explains why we can produce the bug on windows, but only when using the openssl implementation and not after switching to native windows encryption. It also explains why we never observed the bug on iOS devices, or on mac development computers. This may also explain why the last fix helped reduce these crashes (by not refreshing an already refreshed page) but that was a nice optimisation anyway.

The performance impact should not be noticeable. For example, running the whole unit test suite with and without the fix takes the same amount of time.

Possible fix for #2537

@realm-ci
Copy link
Contributor

Please check your coverage here: https://ci.realm.io/job/realm/job/realm-core/job/PR-2616/1/Diff_Coverage

@realm-ci
Copy link
Contributor

Copy link
Contributor

@finnschiermer finnschiermer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!

// decrypt to a temporary buffer first because some implementations may
// require several iterations on a block before producing a final result
// and our shared mappings might be read by other readers at any time
crypt(mode_Decrypt, pos, m_dst_buffer.get(), m_rw_buffer.get(), reinterpret_cast<const char*>(&iv.iv1));
Copy link
Contributor

@rrrlasse rrrlasse May 17, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I couldn't understand this... how about something along the lines of:

We may expect some address ranges of the destination buffer of AESCryptor::read() to stay unmodified, i.e. being overwritten with the same bytes as already present, and may have read-access to these from other threads while decrypting is taking place.

However, some implementations of AES_cbc_encrypt() (in particular OpenSSL) will intermediately put garbled bytes at the destination during operation which will lead to crashes.

We therefore decrypt to a temporary buffer which we memcpy() at the end.

Copy link
Contributor

@rrrlasse rrrlasse left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

awesome!

@realm-ci
Copy link
Contributor

@realm-ci
Copy link
Contributor

Please check your coverage here: https://ci.realm.io/job/realm/job/realm-core/job/PR-2616/2/Diff_Coverage

@ironage ironage merged commit aa67f76 into master May 17, 2017
@ironage ironage deleted the js/decrypt_buffer branch May 17, 2017 17:31
@ironage ironage removed the S:Review label May 17, 2017
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 23, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants