matrix-org / matrix-org/matrix-js-sdk

Null pointer crash in receiveSyncChanges via DehydratedDevices

Open
#5,187 1 comment 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-Element-R O-Uncommon S-Critical T-Defect
Dominant language
TypeScript
Stars
2.2k
Forks
704
Avg merge
1d 20h
Merged PRs (30d)
40

Description

Hello, I am not sure if this is the right place for creating this issue, or if it's an existing issue that's fixed.

## Description

`OlmMachine.receiveSyncChanges` crashes with `"null pointer passed to rust"` when processing device list sync data that involves DehydratedDevices. The crash occurs because the `DehydratedDevices` struct accesses a `Device` reference that is null.

This is unrecoverable — it kills the WASM OlmMachine and prevents all further crypto operations, including room key delivery for message decryption.

## Environment

- `matrix-js-sdk`: 40.1.0
- `@matrix-org/matrix-sdk-crypto-wasm`: ^17.0.0 (resolved via matrix-js-sdk dependency)
- Browser: Chrome 133 (macOS)
- Trigger: Normal `/sync` response processing with bridged rooms (mautrix bridges)

## Steps to Reproduce

1. Initialize MatrixClient with Rust crypto (`initRustCrypto`)
2. Start sync loop
3. Receive a `/sync` response that includes `device_lists` updates
4. `processDeviceLists` calls `receiveSyncChanges({ devices })`
5. The WASM `olmMachine.receiveSyncChanges()` crashes with: `Error: null pointer passed to rust`

## Stack Trace

```
Error: null pointer passed to rust
at OlmMachine.receiveSyncChanges (matrix_sdk_crypto_wasm_bg.wasm)
at RustCrypto.receiveSyncChanges (rust-crypto.js)
```

## Impact

- **Critical**: The crash kills the OlmMachine entirely — no further crypto operations are possible
- All message decryption stops after the crash
- Room key shares delivered via to-device messages are also lost if a catch-all handler returns `[]`

## Current Workaround

We wrap `receiveSyncChanges` to catch the null pointer error and retry without the `devices` parameter, so that to-device events (key shares) are still processed while the problematic device list processing is skipped:

```javascript
const original = crypto.receiveSyncChanges.bind(crypto);
crypto.receiveSyncChanges = async (args) => {
try {
return await original(args);
} catch (err) {
if (err.message?.includes("null pointer")) {
// Retry without device lists to preserve key share processing
const { devices, ...stripped } = args;
return await original(stripped);
}
throw err;
}
};
```

## Expected Behavior

`receiveSyncChanges` should handle null/missing Device references in DehydratedDevices gracefully instead of crashing.

## Additional Context

The crash appears related to the DehydratedDevices struct accessing a Device that was never initialized. This may be triggered by specific device list configurations from mautrix bridge bots.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start at processDeviceLists and RustCrypto.receiveSyncChanges in rust-crypto.js, then inspect the OlmMachine.receiveSyncChanges entry point and the DehydratedDevices handling described in the report. Reproduce with a /sync response containing device-list updates from bridged rooms, and verify that missing Device references no longer crash the WASM OlmMachine while to-device key shares continue processing.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript, wasm
Domain
security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.