1 // Copyright 2020, The Android Open Source Project 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 use crate::error::Error; 16 use nix::sys::mman::{mlock, munlock}; 17 use std::convert::TryFrom; 18 use std::fmt; 19 use std::ops::{Deref, DerefMut}; 20 use std::ptr::write_volatile; 21 22 /// A semi fixed size u8 vector that is zeroed when dropped. It can shrink in 23 /// size but cannot grow larger than the original size (and if it shrinks it 24 /// still owns the entire buffer). Also the data is pinned in memory with 25 /// mlock. 26 #[derive(Default, Eq, PartialEq)] 27 pub struct ZVec { 28 elems: Box<[u8]>, 29 len: usize, 30 } 31 32 impl ZVec { 33 /// Create a ZVec with the given size. new(size: usize) -> Result<Self, Error>34 pub fn new(size: usize) -> Result<Self, Error> { 35 let v: Vec<u8> = vec![0; size]; 36 let b = v.into_boxed_slice(); 37 if size > 0 { 38 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?; 39 } 40 Ok(Self { elems: b, len: size }) 41 } 42 43 /// Reduce the length to the given value. Does nothing if that length is 44 /// greater than the length of the vector. Note that it still owns the 45 /// original allocation even if the length is reduced. reduce_len(&mut self, len: usize)46 pub fn reduce_len(&mut self, len: usize) { 47 if len <= self.elems.len() { 48 self.len = len; 49 } 50 } 51 } 52 53 impl Drop for ZVec { drop(&mut self)54 fn drop(&mut self) { 55 for i in 0..self.elems.len() { 56 unsafe { write_volatile(self.elems.as_mut_ptr().add(i), 0) }; 57 } 58 if !self.elems.is_empty() { 59 if let Err(e) = 60 unsafe { munlock(self.elems.as_ptr() as *const std::ffi::c_void, self.elems.len()) } 61 { 62 log::error!("In ZVec::drop: `munlock` failed: {:?}.", e); 63 } 64 } 65 } 66 } 67 68 impl Deref for ZVec { 69 type Target = [u8]; 70 deref(&self) -> &Self::Target71 fn deref(&self) -> &Self::Target { 72 &self.elems[0..self.len] 73 } 74 } 75 76 impl DerefMut for ZVec { deref_mut(&mut self) -> &mut Self::Target77 fn deref_mut(&mut self) -> &mut Self::Target { 78 &mut self.elems[0..self.len] 79 } 80 } 81 82 impl fmt::Debug for ZVec { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 84 if self.elems.is_empty() { 85 write!(f, "Zvec empty") 86 } else { 87 write!(f, "Zvec size: {} [ Sensitive information redacted ]", self.len) 88 } 89 } 90 } 91 92 impl TryFrom<&[u8]> for ZVec { 93 type Error = Error; 94 try_from(v: &[u8]) -> Result<Self, Self::Error>95 fn try_from(v: &[u8]) -> Result<Self, Self::Error> { 96 let mut z = ZVec::new(v.len())?; 97 if !v.is_empty() { 98 z.clone_from_slice(v); 99 } 100 Ok(z) 101 } 102 } 103 104 impl TryFrom<Vec<u8>> for ZVec { 105 type Error = Error; 106 try_from(mut v: Vec<u8>) -> Result<Self, Self::Error>107 fn try_from(mut v: Vec<u8>) -> Result<Self, Self::Error> { 108 let len = v.len(); 109 // into_boxed_slice calls shrink_to_fit, which may move the pointer. 110 // But sometimes the contents of the Vec are already sensitive and 111 // mustn't be copied. So ensure the shrink_to_fit call is a NOP. 112 v.resize(v.capacity(), 0); 113 let b = v.into_boxed_slice(); 114 if !b.is_empty() { 115 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?; 116 } 117 Ok(Self { elems: b, len }) 118 } 119 } 120