blob: 78b474eae5a9501292a9d54f0f1014c02c182c16 [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
Janis Danisevskis9d90b812020-11-25 21:02:11 -080015use crate::error::Error;
16use nix::sys::mman::{mlock, munlock};
17use std::convert::TryFrom;
18use std::fmt;
19use std::ops::{Deref, DerefMut};
20use std::ptr::write_volatile;
21
Joel Galenson05914582021-01-08 09:30:41 -080022/// 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.
Janis Danisevskis9d90b812020-11-25 21:02:11 -080026#[derive(Default, Eq, PartialEq)]
Joel Galenson05914582021-01-08 09:30:41 -080027pub struct ZVec {
28 elems: Box<[u8]>,
29 len: usize,
30}
Janis Danisevskis9d90b812020-11-25 21:02:11 -080031
32impl ZVec {
33 /// Create a ZVec with the given size.
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 }
Joel Galenson05914582021-01-08 09:30:41 -080040 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.
46 pub fn reduce_len(&mut self, len: usize) {
47 if len <= self.elems.len() {
48 self.len = len;
49 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -080050 }
51}
52
53impl Drop for ZVec {
54 fn drop(&mut self) {
Joel Galenson05914582021-01-08 09:30:41 -080055 for i in 0..self.elems.len() {
56 unsafe { write_volatile(self.elems.as_mut_ptr().add(i), 0) };
Janis Danisevskis9d90b812020-11-25 21:02:11 -080057 }
Joel Galenson05914582021-01-08 09:30:41 -080058 if !self.elems.is_empty() {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080059 if let Err(e) =
Joel Galenson05914582021-01-08 09:30:41 -080060 unsafe { munlock(self.elems.as_ptr() as *const std::ffi::c_void, self.elems.len()) }
Janis Danisevskis9d90b812020-11-25 21:02:11 -080061 {
62 log::error!("In ZVec::drop: `munlock` failed: {:?}.", e);
63 }
64 }
65 }
66}
67
68impl Deref for ZVec {
69 type Target = [u8];
70
71 fn deref(&self) -> &Self::Target {
Joel Galenson05914582021-01-08 09:30:41 -080072 &self.elems[0..self.len]
Janis Danisevskis9d90b812020-11-25 21:02:11 -080073 }
74}
75
76impl DerefMut for ZVec {
77 fn deref_mut(&mut self) -> &mut Self::Target {
Joel Galenson05914582021-01-08 09:30:41 -080078 &mut self.elems[0..self.len]
Janis Danisevskis9d90b812020-11-25 21:02:11 -080079 }
80}
81
82impl fmt::Debug for ZVec {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Joel Galenson05914582021-01-08 09:30:41 -080084 if self.elems.is_empty() {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080085 write!(f, "Zvec empty")
86 } else {
Joel Galenson05914582021-01-08 09:30:41 -080087 write!(f, "Zvec size: {} [ Sensitive information redacted ]", self.len)
Janis Danisevskis9d90b812020-11-25 21:02:11 -080088 }
89 }
90}
91
92impl TryFrom<&[u8]> for ZVec {
93 type Error = Error;
94
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
104impl TryFrom<Vec<u8>> for ZVec {
105 type Error = Error;
106
Paul Crowleye8826e52021-03-31 08:33:53 -0700107 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);
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800113 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 }
Joel Galenson05914582021-01-08 09:30:41 -0800117 Ok(Self { elems: b, len })
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800118 }
119}