[Fix] Harden MTP codec, transport, and SDK security
This commit is contained in:
parent
188caf56cc
commit
a7e804c603
73 changed files with 11892 additions and 5756 deletions
|
|
@ -2,6 +2,7 @@ use mtp_common::CodecError;
|
|||
use mtp_type_map::{PROTOCOL_VERSION, TypeMap, Version};
|
||||
|
||||
use crate::CommunicationValue;
|
||||
use crate::EncodeLimits;
|
||||
|
||||
pub use mtp_type_map::Registry;
|
||||
|
||||
|
|
@ -42,7 +43,41 @@ impl VersionedCodec {
|
|||
|
||||
/// Encode a value using the codec's negotiated framing rules.
|
||||
pub fn encode(&self, value: &CommunicationValue) -> Result<Vec<u8>, CodecError> {
|
||||
value.to_bytes()
|
||||
self.encode_with_limits(value, EncodeLimits::default())
|
||||
}
|
||||
|
||||
/// Encode using an explicit output/resource limit after verifying the
|
||||
/// value belongs to this codec's negotiated type map.
|
||||
pub fn encode_with_limits(
|
||||
&self,
|
||||
value: &CommunicationValue,
|
||||
limits: EncodeLimits,
|
||||
) -> Result<Vec<u8>, CodecError> {
|
||||
let value_map = value.type_map().ok_or(CodecError::MissingTypeMap)?;
|
||||
if value_map.version != self.type_map.version {
|
||||
return Err(CodecError::TypeMapMismatch {
|
||||
expected: self.type_map.version.to_string(),
|
||||
actual: value_map.version.to_string(),
|
||||
});
|
||||
}
|
||||
value.to_bytes_with_limits(limits)
|
||||
}
|
||||
|
||||
/// Explicitly migrate a clear frame to this codec's negotiated type map
|
||||
/// before encoding it.
|
||||
pub fn encode_migrating(&self, value: &CommunicationValue) -> Result<Vec<u8>, CodecError> {
|
||||
self.encode_migrating_with_limits(value, EncodeLimits::default())
|
||||
}
|
||||
|
||||
/// Explicitly migrate and encode with bounded traversal/output.
|
||||
pub fn encode_migrating_with_limits(
|
||||
&self,
|
||||
value: &CommunicationValue,
|
||||
limits: EncodeLimits,
|
||||
) -> Result<Vec<u8>, CodecError> {
|
||||
value
|
||||
.migrate_with_limits(&self.type_map, limits)?
|
||||
.to_bytes_with_limits(limits)
|
||||
}
|
||||
|
||||
/// Decode a frame and retain the negotiated type map for typed access.
|
||||
|
|
@ -58,3 +93,34 @@ impl VersionedCodec {
|
|||
&self.registry
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::DataValue;
|
||||
use mtp_type_map::{CommunicationType, Version};
|
||||
|
||||
#[test]
|
||||
fn encode_rejects_a_value_from_another_negotiated_map() {
|
||||
let mut registry = Registry::new();
|
||||
let version_a = Version::new(3, 0);
|
||||
let version_b = Version::new(4, 0);
|
||||
registry.register(TypeMap::new(version_a.clone()));
|
||||
registry.register(TypeMap::new(version_b.clone()));
|
||||
|
||||
let codec = VersionedCodec::for_version(registry, version_b).expect("codec version");
|
||||
let value = CommunicationValue::new_with_type_map(
|
||||
CommunicationType::Ping,
|
||||
&TypeMap::new(version_a.clone()),
|
||||
)
|
||||
.with_payload(DataValue::Null);
|
||||
|
||||
assert_eq!(
|
||||
codec.encode(&value),
|
||||
Err(CodecError::TypeMapMismatch {
|
||||
expected: "4.0".into(),
|
||||
actual: "3.0".into(),
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue