[WIP] Security work While on holiday

This commit is contained in:
Alex 2026-08-12 22:45:28 +02:00
commit 7f0231e3f1
Signed by: alex
SSH key fingerprint: SHA256:D1+Ub8o0v4K5y1JNivW8IxEOelqLSvPmUzBbDIoZkRQ
109 changed files with 19694 additions and 5210 deletions

View file

@ -1,4 +1,4 @@
use mtp_codec::{CommunicationValue, Version};
use mtp_codec::{CommunicationValue, Version, registry::VersionedCodec};
#[cfg(feature = "pipes")]
use mtp_codec::{DataType, DataValue};
use mtp_common::CommunicationError;
@ -17,6 +17,7 @@ use crate::pipe::{PendingRequest, PipeDispatcher, run_dispatcher};
pub struct MTPConnection {
pub version: Version,
pub codec: VersionedCodec,
pub sender: mtp_transport::Sender,
pub receiver: mtp_transport::Receiver,
pub description: Option<String>,
@ -45,12 +46,19 @@ impl MTPConnection {
request: &CommunicationValue,
expected_response: Option<mtp_codec::CommunicationType>,
) -> Result<CommunicationValue, CommunicationError> {
let request_id = request.get_id();
let request_id = request
.id()
.ok_or_else(|| CommunicationError::Other("request frame must contain an id".into()))?;
if request_id == 0 {
return Err(CommunicationError::Other(
"request frame must have a non-zero id".into(),
));
}
if crate::pipe::is_expired_request(&self.pipe_dispatcher, request_id).await {
return Err(CommunicationError::Other(format!(
"request id {request_id} recently timed out; use a new request id"
)));
}
let (sender, receiver) = tokio::sync::oneshot::channel();
let token = Arc::new(());
@ -86,7 +94,7 @@ impl MTPConnection {
result?
}
Err(_) => {
crate::pipe::remove_pending_request(&self.pipe_dispatcher, request_id, &token)
crate::pipe::expire_pending_request(&self.pipe_dispatcher, request_id, &token)
.await;
return Err(CommunicationError::Other(format!(
"request {request_id} timed out after {:?}",
@ -96,7 +104,7 @@ impl MTPConnection {
};
if let Some(expected) = expected_response {
let expected_type = expected.try_to_id(&mtp_codec::TypeMap::latest());
let expected_type = expected.try_to_id(self.codec.type_map());
if Some(response.get_type()) != expected_type {
return Err(CommunicationError::Other(format!(
"unexpected response type: expected {:?}, got {:?}; parsed {}",
@ -125,23 +133,35 @@ impl MTPConnection {
&self,
description: &str,
) -> Result<crate::pipe::PipeHandle, mtp_common::PipeError> {
let pipe_id = rand::random::<u32>();
let (tx, rx) = tokio::sync::oneshot::channel();
{
let pipe_id = {
let mut pending = self.pipe_dispatcher.pending_creations.lock().await;
let pipe_id = loop {
let candidate = rand::random::<u32>();
if candidate != 0 && !pending.contains_key(&candidate) {
break candidate;
}
};
pending.insert(pipe_id, tx);
pipe_id
};
let request = CommunicationValue::new_with_type_map(
mtp_codec::CommunicationType::PipeRequest,
self.codec.type_map(),
)
.with_id(pipe_id)
.add_typed_default(DataType::Description, DataValue::Str(description.into()));
if let Err(error) = self.sender.send(&request).await {
self.pipe_dispatcher
.pending_creations
.lock()
.await
.remove(&pipe_id);
return Err(mtp_common::PipeError::from(error));
}
let request = CommunicationValue::new(mtp_codec::CommunicationType::PipeRequest)
.with_id(pipe_id)
.add_typed_default(DataType::Description, DataValue::Str(description.into()));
self.sender
.send(&request)
.await
.map_err(mtp_common::PipeError::from)?;
Ok(crate::pipe::PipeHandle {
pipe_id,
description: description.to_string(),
@ -164,11 +184,26 @@ pub(crate) async fn connection_from_parts(
sender: mtp_transport::Sender,
receiver: mtp_transport::Receiver,
version: Version,
codec: VersionedCodec,
#[cfg(feature = "crypto")] auth_state: AuthState,
#[cfg(feature = "crypto")] client_id: u64,
) -> MTPConnection {
#[cfg(feature = "pipes")]
let type_map = codec.type_map().clone();
receiver.set_type_map(codec.type_map()).await;
let remote_addr = sender.handle().remote_addr();
let ping = start_ping_session(&config, sender.clone(), &receiver).await;
#[cfg(feature = "crypto")]
let ping_client_id = client_id;
#[cfg(not(feature = "crypto"))]
let ping_client_id = config.client_id;
let ping = start_ping_session(
&config,
sender.clone(),
&receiver,
codec.type_map(),
ping_client_id,
)
.await;
#[cfg(feature = "pipes")]
{
@ -180,6 +215,9 @@ pub(crate) async fn connection_from_parts(
let dispatcher = Arc::new(PipeDispatcher {
pending_requests: Mutex::new(std::collections::HashMap::new()),
expired_requests: Mutex::new(std::collections::HashMap::new()),
#[cfg(feature = "pipes")]
type_map: type_map.clone(),
pending_creations: Mutex::new(std::collections::HashMap::new()),
pending_pipes: Mutex::new(std::collections::HashMap::new()),
policy: Arc::new(config.policy),
@ -197,6 +235,7 @@ pub(crate) async fn connection_from_parts(
MTPConnection {
version,
codec,
sender,
receiver,
app_rx: Mutex::new(app_rx),
@ -221,11 +260,15 @@ pub(crate) async fn connection_from_parts(
);
let dispatcher = Arc::new(PipeDispatcher {
pending_requests: Mutex::new(std::collections::HashMap::new()),
expired_requests: Mutex::new(std::collections::HashMap::new()),
#[cfg(feature = "pipes")]
type_map,
});
let task = tokio::spawn(run_dispatcher(receiver.clone(), app_tx, dispatcher.clone()));
MTPConnection {
version,
codec,
sender,
receiver,
app_rx: Mutex::new(app_rx),