blob: c917a89843502c497ad8977aea01fd100942277e [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 Danisevskisa16ddf32021-10-20 09:40:02 -070015//! Implements ZVec, a vector that is mlocked during its lifetime and zeroed
16//! when dropped.
17
Janis Danisevskis9d90b812020-11-25 21:02:11 -080018use 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
Janis Danisevskisa16ddf32021-10-20 09:40:02 -070034/// ZVec specific error codes.
35#[derive(Debug, thiserror::Error, Eq, PartialEq)]
36pub enum Error {
37 /// Underlying libc error.
38 #[error(transparent)]
39 NixError(#[from] nix::Error),
40}
41
Janis Danisevskis9d90b812020-11-25 21:02:11 -080042impl ZVec {
43 /// Create a ZVec with the given size.
44 pub fn new(size: usize) -> Result<Self, Error> {
45 let v: Vec<u8> = vec![0; size];
46 let b = v.into_boxed_slice();
47 if size > 0 {
Andrew Walbrana47698a2023-07-21 17:23:56 +010048 // SAFETY: The address range is part of our address space.
Janis Danisevskis9d90b812020-11-25 21:02:11 -080049 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
50 }
Joel Galenson05914582021-01-08 09:30:41 -080051 Ok(Self { elems: b, len: size })
52 }
53
54 /// Reduce the length to the given value. Does nothing if that length is
55 /// greater than the length of the vector. Note that it still owns the
56 /// original allocation even if the length is reduced.
57 pub fn reduce_len(&mut self, len: usize) {
58 if len <= self.elems.len() {
59 self.len = len;
60 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -080061 }
Janis Danisevskis46e97c82021-10-20 09:14:03 -070062
63 /// Attempts to make a clone of the Zvec. This may fail due trying to mlock
64 /// the new memory region.
65 pub fn try_clone(&self) -> Result<Self, Error> {
66 let mut result = Self::new(self.len())?;
67 result[..].copy_from_slice(&self[..]);
68 Ok(result)
69 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -080070}
71
72impl Drop for ZVec {
73 fn drop(&mut self) {
Joel Galenson05914582021-01-08 09:30:41 -080074 for i in 0..self.elems.len() {
Andrew Walbrana47698a2023-07-21 17:23:56 +010075 // SAFETY: The pointer is valid and properly aligned because it came from a reference.
76 unsafe { write_volatile(&mut self.elems[i], 0) };
Janis Danisevskis9d90b812020-11-25 21:02:11 -080077 }
Joel Galenson05914582021-01-08 09:30:41 -080078 if !self.elems.is_empty() {
Janis Danisevskis9d90b812020-11-25 21:02:11 -080079 if let Err(e) =
Andrew Walbrana47698a2023-07-21 17:23:56 +010080 // SAFETY: The address range is part of our address space, and was previously locked
81 // by `mlock` in `ZVec::new` or the `TryFrom<Vec<u8>>` implementation.
82 unsafe {
83 munlock(self.elems.as_ptr() as *const std::ffi::c_void, self.elems.len())
84 }
Janis Danisevskis9d90b812020-11-25 21:02:11 -080085 {
86 log::error!("In ZVec::drop: `munlock` failed: {:?}.", e);
87 }
88 }
89 }
90}
91
92impl Deref for ZVec {
93 type Target = [u8];
94
95 fn deref(&self) -> &Self::Target {
Joel Galenson05914582021-01-08 09:30:41 -080096 &self.elems[0..self.len]
Janis Danisevskis9d90b812020-11-25 21:02:11 -080097 }
98}
99
100impl DerefMut for ZVec {
101 fn deref_mut(&mut self) -> &mut Self::Target {
Joel Galenson05914582021-01-08 09:30:41 -0800102 &mut self.elems[0..self.len]
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800103 }
104}
105
106impl fmt::Debug for ZVec {
107 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
Joel Galenson05914582021-01-08 09:30:41 -0800108 if self.elems.is_empty() {
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800109 write!(f, "Zvec empty")
110 } else {
Joel Galenson05914582021-01-08 09:30:41 -0800111 write!(f, "Zvec size: {} [ Sensitive information redacted ]", self.len)
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800112 }
113 }
114}
115
116impl TryFrom<&[u8]> for ZVec {
117 type Error = Error;
118
119 fn try_from(v: &[u8]) -> Result<Self, Self::Error> {
120 let mut z = ZVec::new(v.len())?;
121 if !v.is_empty() {
122 z.clone_from_slice(v);
123 }
124 Ok(z)
125 }
126}
127
128impl TryFrom<Vec<u8>> for ZVec {
129 type Error = Error;
130
Paul Crowleye8826e52021-03-31 08:33:53 -0700131 fn try_from(mut v: Vec<u8>) -> Result<Self, Self::Error> {
132 let len = v.len();
133 // into_boxed_slice calls shrink_to_fit, which may move the pointer.
134 // But sometimes the contents of the Vec are already sensitive and
135 // mustn't be copied. So ensure the shrink_to_fit call is a NOP.
136 v.resize(v.capacity(), 0);
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800137 let b = v.into_boxed_slice();
138 if !b.is_empty() {
Andrew Walbrana47698a2023-07-21 17:23:56 +0100139 // SAFETY: The address range is part of our address space.
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800140 unsafe { mlock(b.as_ptr() as *const std::ffi::c_void, b.len()) }?;
141 }
Joel Galenson05914582021-01-08 09:30:41 -0800142 Ok(Self { elems: b, len })
Janis Danisevskis9d90b812020-11-25 21:02:11 -0800143 }
144}