blob: 52addfcbc2e885989ea702bba61aaafe13f8175f [file] [log] [blame]
Janis Danisevskis9d90b812020-11-25 21:02:11 -08001// 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#![allow(dead_code)]
16
17use crate::error::Error;
18use nix::sys::mman::{mlock, munlock};
19use std::convert::TryFrom;
20use std::fmt;
21use std::ops::{Deref, DerefMut};
22use std::ptr::write_volatile;
23
24/// A fixed size u8 vector that is zeroed when dropped. Also the data is
25/// pinned in memory with mlock.
26#[derive(Default, Eq, PartialEq)]
27pub struct ZVec(Box<[u8]>);
28
29impl ZVec {
30 /// Create a ZVec with the given size.
31 pub fn new(size: usize) -> Result<Self, Error> {
32 let v: Vec<u8> = vec![0; size];
33 let b = v.into_boxed_slice();
34 if size > 0 {
35 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
36 }
37 Ok(Self(b))
38 }
39}
40
41impl Drop for ZVec {
42 fn drop(&mut self) {
43 for i in 0..self.0.len() {
44 unsafe { write_volatile(self.0.as_mut_ptr().add(i), 0) };
45 }
46 if !self.0.is_empty() {
47 if let Err(e) =
48 unsafe { munlock(self.0.as_ptr() as *const std::ffi::c_void, self.0.len()) }
49 {
50 log::error!("In ZVec::drop: `munlock` failed: {:?}.", e);
51 }
52 }
53 }
54}
55
56impl Deref for ZVec {
57 type Target = [u8];
58
59 fn deref(&self) -> &Self::Target {
60 &self.0
61 }
62}
63
64impl DerefMut for ZVec {
65 fn deref_mut(&mut self) -> &mut Self::Target {
66 &mut self.0
67 }
68}
69
70impl fmt::Debug for ZVec {
71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
72 if self.0.is_empty() {
73 write!(f, "Zvec empty")
74 } else {
75 write!(f, "Zvec size: {} [ Sensitive information redacted ]", self.0.len())
76 }
77 }
78}
79
80impl TryFrom<&[u8]> for ZVec {
81 type Error = Error;
82
83 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
84 let mut z = ZVec::new(v.len())?;
85 if !v.is_empty() {
86 z.clone_from_slice(v);
87 }
88 Ok(z)
89 }
90}
91
92impl TryFrom<Vec<u8>> for ZVec {
93 type Error = Error;
94
95 fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
96 let b = v.into_boxed_slice();
97 if !b.is_empty() {
98 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
99 }
100 Ok(Self(b))
101 }
102}