Skip to content

Commit cbab388

Browse files
committed
fix: Consolidate lock scope for transaction registry
1 parent 5a9c74c commit cbab388

File tree

1 file changed

+19
-23
lines changed

1 file changed

+19
-23
lines changed

native/ecto_libsql/src/lib.rs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,29 +1210,18 @@ fn declare_cursor_with_context(
12101210
.collect::<Result<_, _>>()
12111211
.map_err(|e| rustler::Error::Term(Box::new(e)))?;
12121212

1213-
// Determine conn_id for cursor ownership tracking
1214-
let conn_id = if id_type == transaction() {
1215-
// For transaction, get conn_id from TransactionEntry
1216-
let txn_registry = safe_lock(&TXN_REGISTRY, "declare_cursor_with_context txn")?;
1217-
let entry = txn_registry
1218-
.get(id)
1219-
.ok_or_else(|| rustler::Error::Term(Box::new("Transaction not found")))?;
1220-
entry.conn_id.clone()
1221-
} else if id_type == connection() {
1222-
// For connection, use the id directly
1223-
id.to_string()
1224-
} else {
1225-
return Err(rustler::Error::Term(Box::new("Invalid id_type for cursor")));
1226-
};
1227-
1228-
let (columns, rows) = if id_type == transaction() {
1229-
// Use transaction registry
1213+
let (conn_id, columns, rows) = if id_type == transaction() {
1214+
// CONSOLIDATED LOCK SCOPE: Prevent TOCTOU by holding lock for both conn_id lookup and query execution
12301215
let mut txn_registry = safe_lock(&TXN_REGISTRY, "declare_cursor_with_context txn")?;
12311216
let entry = txn_registry
12321217
.get_mut(id)
12331218
.ok_or_else(|| rustler::Error::Term(Box::new("Transaction not found")))?;
12341219

1235-
TOKIO_RUNTIME.block_on(async {
1220+
// Capture conn_id while we hold the lock
1221+
let conn_id_for_cursor = entry.conn_id.clone();
1222+
1223+
// Execute query without releasing the lock
1224+
let (cols, rows) = TOKIO_RUNTIME.block_on(async {
12361225
let mut result_rows = entry
12371226
.transaction
12381227
.query(sql, decoded_args)
@@ -1266,9 +1255,12 @@ fn declare_cursor_with_context(
12661255
}
12671256

12681257
Ok::<_, rustler::Error>((columns, rows))
1269-
})?
1270-
} else {
1271-
// Use connection registry
1258+
})?;
1259+
1260+
(conn_id_for_cursor, cols, rows)
1261+
} else if id_type == connection() {
1262+
// For connection, use the id directly
1263+
let conn_id_for_cursor = id.to_string();
12721264
let conn_map = safe_lock(&CONNECTION_REGISTRY, "declare_cursor_with_context conn")?;
12731265
let client = conn_map
12741266
.get(id)
@@ -1277,7 +1269,7 @@ fn declare_cursor_with_context(
12771269

12781270
drop(conn_map);
12791271

1280-
TOKIO_RUNTIME.block_on(async {
1272+
let (cols, rows) = TOKIO_RUNTIME.block_on(async {
12811273
let client_guard = safe_lock_arc(&client, "declare_cursor_with_context client")?;
12821274
let conn_guard =
12831275
safe_lock_arc(&client_guard.client, "declare_cursor_with_context conn")?;
@@ -1314,7 +1306,11 @@ fn declare_cursor_with_context(
13141306
}
13151307

13161308
Ok::<_, rustler::Error>((columns, rows))
1317-
})?
1309+
})?;
1310+
1311+
(conn_id_for_cursor, cols, rows)
1312+
} else {
1313+
return Err(rustler::Error::Term(Box::new("Invalid id_type for cursor")));
13181314
};
13191315

13201316
let cursor_id = Uuid::new_v4().to_string();

0 commit comments

Comments
 (0)