blob: e75e1dc82a3e09d0689014ae2d33d207a34ee03e [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
Joel Galenson05914582021-01-08 09:30:41 -080024/// A semi fixed size u8 vector that is zeroed when dropped. It can shrink in
25/// size but cannot grow larger than the original size (and if it shrinks it
26/// still owns the entire buffer). Also the data is pinned in memory with
27/// mlock.
Janis Danisevskis9d90b812020-11-25 21:02:11 -080028#[derive(Default, Eq, PartialEq)]
Joel Galenson05914582021-01-08 09:30:41 -080029pub struct ZVec {
30 elems: Box<[u8]>,
31 len: usize,
32}
Janis Danisevskis9d90b812020-11-25 21:02:11 -080033
34impl ZVec {
35 /// Create a ZVec with the given size.
36 pub fn new(size: usize) -> Result<Self, Error> {
37 let v: Vec<u8> = vec![0; size];
38 let b = v.into_boxed_slice();
39 if size > 0 {
40 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
41 }
Joel Galenson05914582021-01-08 09:30:41 -080042 Ok(Self { elems: b, len: size })
43 }
44
45 /// Reduce the length to the given value. Does nothing if that length is
46 /// greater than the length of the vector. Note that it still owns the
47 /// original allocation even if the length is reduced.
48 pub fn reduce_len(&mut self, len: usize) {
49 if len <= self.elems.len() {
50 self.len = len;
51 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -080052 }
53}
54
55impl Drop for ZVec {
56 fn drop(&mut self) {
Joel Galenson05914582021-01-08 09:30:41 -080057 for i in 0..self.elems.len() {
58 unsafe { write_volatile(self.elems.as_mut_ptr().add(i), 0) };
Janis Danisevskis9d90b812020-11-25 21:02:11 -080059 }
Joel Galenson05914582021-01-08 09:30:41 -080060 if !self.elems.is_empty() {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080061 if let Err(e) =
Joel Galenson05914582021-01-08 09:30:41 -080062 unsafe { munlock(self.elems.as_ptr() as *const std::ffi::c_void, self.elems.len()) }
Janis Danisevskis9d90b812020-11-25 21:02:11 -080063 {
64 log::error!("In ZVec::drop: `munlock` failed: {:?}.", e);
65 }
66 }
67 }
68}
69
70impl Deref for ZVec {
71 type Target = [u8];
72
73 fn deref(&self) -> &Self::Target {
Joel Galenson05914582021-01-08 09:30:41 -080074 &self.elems[0..self.len]
Janis Danisevskis9d90b812020-11-25 21:02:11 -080075 }
76}
77
78impl DerefMut for ZVec {
79 fn deref_mut(&mut self) -> &mut Self::Target {
Joel Galenson05914582021-01-08 09:30:41 -080080 &mut self.elems[0..self.len]
Janis Danisevskis9d90b812020-11-25 21:02:11 -080081 }
82}
83
84impl fmt::Debug for ZVec {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Joel Galenson05914582021-01-08 09:30:41 -080086 if self.elems.is_empty() {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080087 write!(f, "Zvec empty")
88 } else {
Joel Galenson05914582021-01-08 09:30:41 -080089 write!(f, "Zvec size: {} [ Sensitive information redacted ]", self.len)
Janis Danisevskis9d90b812020-11-25 21:02:11 -080090 }
91 }
92}
93
94impl TryFrom<&[u8]> for ZVec {
95 type Error = Error;
96
97 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
98 let mut z = ZVec::new(v.len())?;
99 if !v.is_empty() {
100 z.clone_from_slice(v);
101 }
102 Ok(z)
103 }
104}
105
106impl TryFrom<Vec<u8>> for ZVec {
107 type Error = Error;
108
109 fn try_from(v: Vec<u8>) -> Result<Self, Self::Error> {
110 let b = v.into_boxed_slice();
111 if !b.is_empty() {
112 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
113 }
Joel Galenson05914582021-01-08 09:30:41 -0800114 let len = b.len();
115 Ok(Self { elems: b, len })
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800116 }
117}