Lock decryption in CtrEncryptedBacking

This prevents a race where two threads could read at the same time and
end up using the wrong IV leading to garbage data being read. This
caused crashes in several games including Celeste.
This commit is contained in:
◱ PixelyIon 2021-02-18 11:43:59 +00:00 committed by ◱ Mark
parent ce0e032255
commit 31db70f1d4
3 changed files with 12 additions and 4 deletions

View File

@ -9,6 +9,7 @@
namespace skyline::crypto { namespace skyline::crypto {
/** /**
* @brief Wrapper for mbedtls for AES decryption using a cipher * @brief Wrapper for mbedtls for AES decryption using a cipher
* @note The IV state must be appropriately locked during multi-threaded usage
*/ */
class AesCipher { class AesCipher {
private: private:

View File

@ -22,11 +22,14 @@ namespace skyline::vfs {
size_t sectorOffset{offset % SectorSize}; size_t sectorOffset{offset % SectorSize};
if (sectorOffset == 0) { if (sectorOffset == 0) {
UpdateCtr(baseOffset + offset);
size_t read{backing->Read(output, offset)}; size_t read{backing->Read(output, offset)};
if (read != size) if (read != size)
return 0; return 0;
{
std::lock_guard guard(mutex);
UpdateCtr(baseOffset + offset);
cipher.Decrypt(output); cipher.Decrypt(output);
}
return size; return size;
} }
@ -35,8 +38,11 @@ namespace skyline::vfs {
size_t read{backing->Read(blockBuf, sectorStart)}; size_t read{backing->Read(blockBuf, sectorStart)};
if (read != SectorSize) if (read != SectorSize)
return 0; return 0;
{
std::lock_guard guard(mutex);
UpdateCtr(baseOffset + sectorStart); UpdateCtr(baseOffset + sectorStart);
cipher.Decrypt(blockBuf); cipher.Decrypt(blockBuf);
}
if (size + sectorOffset < SectorSize) { if (size + sectorOffset < SectorSize) {
std::memcpy(output.data(), blockBuf.data() + sectorOffset, size); std::memcpy(output.data(), blockBuf.data() + sectorOffset, size);
return size; return size;

View File

@ -16,6 +16,7 @@ namespace skyline::vfs {
crypto::KeyStore::Key128 ctr; crypto::KeyStore::Key128 ctr;
crypto::AesCipher cipher; crypto::AesCipher cipher;
std::shared_ptr<Backing> backing; std::shared_ptr<Backing> backing;
std::mutex mutex; //!< Synchronize all AES-CTR cipher state modifications
size_t baseOffset; //!< The offset of the backing into the file is used to calculate the IV size_t baseOffset; //!< The offset of the backing into the file is used to calculate the IV
/** /**