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

fix(concurrency): handle simultaneous (a)finalize calls #19

Closed
3 tasks done
rmlibre opened this issue Jul 10, 2024 · 1 comment
Closed
3 tasks done

fix(concurrency): handle simultaneous (a)finalize calls #19

rmlibre opened this issue Jul 10, 2024 · 1 comment
Assignees
Labels
bug Something isn't working

Comments

@rmlibre
Copy link
Owner

rmlibre commented Jul 10, 2024

Is this a new bug in aiootp?

  • This affects a supported version of aiootp
  • This isn't a security vulnerability or issue
  • I've searched the existing issues, & I couldn't find one for this bug

Issue

Cipher streaming object (a)finalize calls can be made simultaneously in concurrent contexts, leading to invalid data processing.

Remediation

Utilize ConcurrencyGuard and atomic deque objects to track and allow the first call to (a)finalize while raising IncoherentConcurrencyState for all other calls.

self._finalizing_now.append(token := token_bytes(32))
if not compare_digest(token, self._finalizing_now[0]):
raise ConcurrencyGuard.IncoherentConcurrencyState
async with ConcurrencyGuard(self._digesting_now, token=token):
end_padding = await self._padding.aend_padding(self._byte_count)
final_blocks = abatch(
self._buffer.pop() + end_padding,
size=self._config.BLOCKSIZE,
)
async for block in final_blocks:
self._buffer.append(block)
while self._buffer:
block = await self._stream.asend(None)
block_id = await self.shmac.anext_block_id(block)
yield block_id, block
await self.shmac.afinalize()

self._finalizing_now.append(token := token_bytes(32))
if not compare_digest(token, self._finalizing_now[0]):
raise ConcurrencyGuard.IncoherentConcurrencyState
async with ConcurrencyGuard(self._digesting_now, token=token):
await self.shmac.afinalize()
async for result in self:
yield result
queue = self._result_queue
footer_index = await self._padding.adepadding_end_index(
queue[-1]
)
async for block in abatch(
b"".join(queue)[:footer_index], size=self._config.BLOCKSIZE
):
yield block


The buffers that are queued to run before the (a)finalize call are allowed to finish, but all buffers queued to run afterwards raise CipherStreamIsClosed.

async with ConcurrencyGuard(self._digesting_now):
if (
self._finalizing_now
and self._finalizing_now[0] not in self._digesting_now
):
raise CipherStreamIssue.stream_has_been_closed()

async with ConcurrencyGuard(self._digesting_now):
if (
self._finalizing_now
and self._finalizing_now[0] not in self._digesting_now
):
raise CipherStreamIssue.stream_has_been_closed()


Tests were written to ensure the correct exception is raised.

Environment

- OS: Any
- Python: >=3.8
- aiootp: < 0.23.11

Additional Context

Refs (bd5cd12)

@rmlibre rmlibre added the bug Something isn't working label Jul 10, 2024
@rmlibre rmlibre self-assigned this Jul 10, 2024
@rmlibre rmlibre changed the title [DRAFT] fix(concurrency): handle simultaneous (a)finalize calls fix(concurrency): handle simultaneous (a)finalize calls Aug 10, 2024
@rmlibre
Copy link
Owner Author

rmlibre commented Aug 10, 2024

Resolved by (1bdbfba, 3d70ea9)

@rmlibre rmlibre closed this as completed Aug 10, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

1 participant