use crate::binder::Stability;
use crate::error::{Result, StatusCode};
use crate::{
Deserialize, Parcel, Parcelable, ParcelableMetadata, Serialize, NON_NULL_PARCELABLE_FLAG,
NULL_PARCELABLE_FLAG,
};
use std::any::Any;
use std::sync::{Arc, Mutex};
trait AnyParcelable: Parcelable + std::fmt::Debug + Send + Sync + 'static {
fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync>;
}
impl<T: Parcelable + std::fmt::Debug + Send + Sync + 'static> AnyParcelable for T {
fn into_any_arc(self: Arc<Self>) -> Arc<dyn Any + Send + Sync> {
self
}
}
#[derive(Debug)]
enum ParcelableHolderData {
Empty,
Parcelable {
parcelable: Arc<dyn AnyParcelable>,
name: String,
},
Parcel(Box<Parcel>),
}
#[derive(Debug)]
pub struct ParcelableHolder {
data: Mutex<ParcelableHolderData>,
stability: Stability,
}
impl Default for ParcelableHolder {
fn default() -> Self {
Self::new(Stability::Local)
}
}
impl ParcelableHolder {
pub fn new(stability: Stability) -> Self {
Self {
data: Mutex::new(ParcelableHolderData::Empty),
stability,
}
}
pub fn reset(&mut self) {
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Empty;
}
pub fn set_parcelable<T>(&mut self, p: Arc<T>) -> Result<()>
where
T: Any + Parcelable + ParcelableMetadata + std::fmt::Debug + Send + Sync,
{
if !p.stability().includes(self.stability) {
log::error!(
"ParcelableHolder::set_parcelable: parcelable stability {:?} does not include holder stability {:?}",
p.stability(),
self.stability
);
return Err(StatusCode::BadValue);
}
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Parcelable {
parcelable: p,
name: T::descriptor().into(),
};
Ok(())
}
pub fn get_parcelable<T>(&self) -> Result<Option<Arc<T>>>
where
T: Any + Parcelable + ParcelableMetadata + Default + std::fmt::Debug + Send + Sync,
{
let parcelable_desc = T::descriptor();
let mut data = self.data.lock().expect("Parcelable holder lock poisoned");
match *data {
ParcelableHolderData::Empty => Ok(None),
ParcelableHolderData::Parcelable {
ref parcelable,
ref name,
} => {
if name != parcelable_desc {
log::error!(
"ParcelableHolder::get_parcelable: parcelable descriptor mismatch: {name:?} != {parcelable_desc:?}");
return Err(StatusCode::BadValue);
}
match Arc::clone(parcelable).into_any_arc().downcast::<T>() {
Err(_) => {
log::error!("ParcelableHolder::get_parcelable: parcelable type mismatch: {parcelable:?} != {parcelable_desc:?}");
Err(StatusCode::BadValue)
}
Ok(x) => Ok(Some(x)),
}
}
ParcelableHolderData::Parcel(ref mut parcel) => {
parcel.set_data_position(0);
let name: String = parcel.read()?;
if name != parcelable_desc {
return Ok(None);
}
let mut parcelable = T::default();
parcelable.read_from_parcel(parcel)?;
let parcelable = Arc::new(parcelable);
let result = Arc::clone(&parcelable);
*data = ParcelableHolderData::Parcelable { parcelable, name };
Ok(Some(result))
}
}
}
pub fn get_stability(&self) -> Stability {
self.stability
}
}
impl Serialize for ParcelableHolder {
fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
parcel.write(&NON_NULL_PARCELABLE_FLAG)?;
self.write_to_parcel(parcel)
}
}
impl Deserialize for ParcelableHolder {
fn deserialize(parcel: &mut Parcel) -> Result<Self> {
let status: i32 = parcel.read()?;
if status == NULL_PARCELABLE_FLAG {
log::error!("ParcelableHolder::deserialize: unexpected null");
Err(StatusCode::UnexpectedNull)
} else if status == NON_NULL_PARCELABLE_FLAG {
let mut parcelable = ParcelableHolder::default();
parcelable.read_from_parcel(parcel)?;
Ok(parcelable)
} else {
Err(StatusCode::UnexpectedNull)
}
}
fn deserialize_from(&mut self, parcel: &mut Parcel) -> Result<()> {
let status: i32 = parcel.read()?;
if status == NULL_PARCELABLE_FLAG {
log::error!("ParcelableHolder::deserialize_from: unexpected null");
Err(StatusCode::UnexpectedNull)
} else if status == NON_NULL_PARCELABLE_FLAG {
self.read_from_parcel(parcel)
} else {
Err(StatusCode::UnexpectedNull)
}
}
}
fn parcelable_stability_repr(stability: Stability) -> i32 {
match stability {
Stability::Vintf => 1, _ => 0, }
}
impl Parcelable for ParcelableHolder {
fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
let stability = parcelable_stability_repr(self.stability);
parcel.write(&stability)?;
let mut data = self.data.lock().expect("Parcelable holder lock poisoned");
match *data {
ParcelableHolderData::Empty => parcel.write(&0i32),
ParcelableHolderData::Parcelable {
ref parcelable,
ref name,
} => {
let length_start = parcel.data_position();
parcel.write(&0i32)?;
let data_start = parcel.data_position();
parcel.write(name)?;
parcelable.write_to_parcel(parcel)?;
let end = parcel.data_position();
parcel.set_data_position(length_start);
assert!(end >= data_start);
parcel.write(&((end - data_start) as i32))?;
parcel.set_data_position(end);
Ok(())
}
ParcelableHolderData::Parcel(ref mut p) => {
parcel.write(&(p.data_size() as i32))?;
parcel.append_all_from(p)
}
}
}
fn read_from_parcel(&mut self, parcel: &mut Parcel) -> Result<()> {
let wire_stability: i32 = parcel.read()?;
let local_stability = parcelable_stability_repr(self.stability);
if local_stability != wire_stability {
log::error!(
"ParcelableHolder::read_from_parcel: parcelable stability mismatch: {:?} != {:?}",
self.stability,
wire_stability
);
return Err(StatusCode::BadValue);
}
let data_size: i32 = parcel.read()?;
if data_size < 0 {
return Err(StatusCode::BadValue);
}
if data_size == 0 {
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") = ParcelableHolderData::Empty;
return Ok(());
}
let data_start: usize = parcel.data_position();
let data_end: usize = data_start
.checked_add(data_size as usize)
.ok_or(StatusCode::BadValue)?;
let mut new_parcel = Parcel::new();
#[cfg(feature = "rpc")]
if !parcel.is_kernel_backed() {
new_parcel.set_for_rpc(true);
if let Some(ops) = parcel.rpc_ops() {
new_parcel.attach_rpc_ops(ops);
}
}
new_parcel.append_from(parcel, data_start, data_size as usize)?;
*self
.data
.get_mut()
.expect("Parcelable holder lock poisoned") =
ParcelableHolderData::Parcel(Box::new(new_parcel));
parcel.set_data_position(data_end);
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn holder_serializes_parcelable_stability_not_binder_level_bitmask() {
let vintf = ParcelableHolder::new(Stability::Vintf);
let mut vp = Parcel::new();
vintf.write_to_parcel(&mut vp).unwrap();
vp.set_data_position(0);
let vintf_wire: i32 = vp.read().unwrap();
assert_eq!(
vintf_wire, 1,
"Vintf holder must serialize as STABILITY_VINTF (1)"
);
let local = ParcelableHolder::default();
let mut lp = Parcel::new();
local.write_to_parcel(&mut lp).unwrap();
lp.set_data_position(0);
let local_wire: i32 = lp.read().unwrap();
assert_eq!(
local_wire, 0,
"Local holder must serialize as STABILITY_LOCAL (0)"
);
vp.set_data_position(0);
let mut dst = ParcelableHolder::new(Stability::Vintf);
dst.read_from_parcel(&mut vp).unwrap();
vp.set_data_position(0);
let mut local_dst = ParcelableHolder::default();
assert!(matches!(
local_dst.read_from_parcel(&mut vp),
Err(StatusCode::BadValue)
));
}
#[test]
fn holder_rejects_null_and_garbage_sentinels() {
for status in [NULL_PARCELABLE_FLAG, 2, -1] {
let mut p = Parcel::new();
p.write(&status).unwrap();
p.set_data_position(0);
assert!(
matches!(
ParcelableHolder::deserialize(&mut p),
Err(StatusCode::UnexpectedNull)
),
"status {status} must be rejected as UnexpectedNull",
);
}
}
#[cfg(feature = "rpc")]
#[test]
fn a_forged_object_inside_a_holder_never_becomes_a_binder() {
#[derive(Debug, Default)]
struct BinderCarrier {
binder: Option<crate::SIBinder>,
}
impl ParcelableMetadata for BinderCarrier {
fn descriptor() -> &'static str {
"rsbinder.test.BinderCarrier"
}
}
impl Parcelable for BinderCarrier {
fn write_to_parcel(&self, parcel: &mut Parcel) -> Result<()> {
parcel.write(&self.binder)
}
fn read_from_parcel(&mut self, parcel: &mut Parcel) -> Result<()> {
self.binder = parcel.read()?;
Ok(())
}
}
let mut payload = Parcel::new_data_only();
payload
.write(&BinderCarrier::descriptor().to_string())
.unwrap();
payload
.write(&crate::binder_object::flat_binder_object::new_handle(0, 0))
.unwrap();
payload.write(&0i32).unwrap();
let payload = payload.into_bytes().unwrap();
let mut encoded = Parcel::new_data_only();
encoded.write(&NON_NULL_PARCELABLE_FLAG).unwrap();
encoded.write(&0i32).unwrap(); encoded.write(&(payload.len() as i32)).unwrap();
encoded.write_aligned_data(&payload).unwrap();
let encoded = encoded.into_bytes().unwrap();
let holder: ParcelableHolder = crate::from_bytes(&encoded).expect("the holder decodes");
assert_eq!(
holder.get_parcelable::<BinderCarrier>().err(),
Some(StatusCode::BadType),
"the payload of a data-only holder must stay data-only"
);
}
#[cfg(feature = "rpc")]
#[test]
fn a_data_only_holder_is_refused_by_a_kernel_parcel() {
let mut payload = Parcel::new_data_only();
payload
.write(&"rsbinder.test.BinderCarrier".to_string())
.unwrap();
payload
.write(&crate::binder_object::flat_binder_object::new_handle(0, 0))
.unwrap();
payload.write(&0i32).unwrap();
let payload = payload.into_bytes().unwrap();
let mut encoded = Parcel::new_data_only();
encoded.write(&NON_NULL_PARCELABLE_FLAG).unwrap();
encoded.write(&0i32).unwrap(); encoded.write(&(payload.len() as i32)).unwrap();
encoded.write_aligned_data(&payload).unwrap();
let encoded = encoded.into_bytes().unwrap();
let holder: ParcelableHolder = crate::from_bytes(&encoded).expect("the holder decodes");
let mut kernel = Parcel::new();
assert_eq!(
kernel.write(&holder).err(),
Some(StatusCode::BadType),
"a data-only payload must not be relayed into a kernel parcel"
);
let mut data_only = Parcel::new_data_only();
data_only
.write(&holder)
.expect("a same-mode sink still accepts the holder");
}
}