Skip to content

Commit 09efdc9

Browse files
committed
fix(snapshot): switch PCI snapshot state vectors for arrays
Using serde-big-array, switch to serializing arrays rather than converting arrays to vecs. This should prevent panics that could previously be encountered by unwrapping vec-to-array conversions (e.g., when a malformed snapshot was encountered). NB: Arrays must be boxed to prevent stack overflows. This is still better than using Vecs, because the size is known at compile time. Signed-off-by: James Curtis <jxcurtis@amazon.co.uk>
1 parent 6673d4d commit 09efdc9

2 files changed

Lines changed: 39 additions & 12 deletions

File tree

src/vmm/src/devices/virtio/transport/pci/device.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,15 @@ const NOTIFY_OFF_MULTIPLIER: u32 = 4; // A dword per notification address.
221221
const VIRTIO_PCI_VENDOR_ID: u16 = 0x1af4;
222222
const VIRTIO_PCI_DEVICE_ID_BASE: u16 = 0x1040; // Add to device type to get device ID.
223223

224+
/// The size of the VIRTIO_PCI_CAP_PCI_CFG capability.
225+
const CAP_PCI_CFG_SIZE: usize = std::mem::size_of::<VirtioPciCfgCap>();
226+
224227
#[derive(Debug, Clone, Serialize, Deserialize)]
225228
pub struct VirtioPciDeviceState {
226229
pub sbdf: PciSBDF,
227230
pub device_activated: bool,
228231
pub cap_pci_cfg_offset: u16,
229-
pub cap_pci_cfg: Vec<u8>,
232+
pub cap_pci_cfg: [u8; CAP_PCI_CFG_SIZE],
230233
pub pci_configuration_state: PciConfigurationState,
231234
pub pci_dev_state: VirtioPciCommonConfigState,
232235
pub msix_state: MsixConfigState,
@@ -610,7 +613,8 @@ impl VirtioPciDevice {
610613
sbdf: self.sbdf,
611614
device_activated: self.device_activated.load(Ordering::Acquire),
612615
cap_pci_cfg_offset: self.cap_pci_cfg_info.offset,
613-
cap_pci_cfg: self.cap_pci_cfg_info.cap.bytes().to_vec(),
616+
cap_pci_cfg: <[u8; CAP_PCI_CFG_SIZE]>::try_from(self.cap_pci_cfg_info.cap.as_slice())
617+
.unwrap(),
614618
pci_configuration_state: self.configuration.state(),
615619
pci_dev_state: self.common_config.state(),
616620
msix_state: self

src/vmm/src/pci/configuration.rs

Lines changed: 33 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,26 @@ use crate::pci::{PciCapabilityId, PciClassCode};
1818
// The number of 32bit registers in the config space, 4096 bytes.
1919
const NUM_CONFIGURATION_REGISTERS: usize = 1024;
2020

21+
mod boxed_big_array {
22+
use serde::{Deserializer, Serializer};
23+
use serde_big_array::BigArray;
24+
25+
use super::NUM_CONFIGURATION_REGISTERS;
26+
27+
pub fn serialize<S: Serializer>(
28+
val: &Box<[u32; NUM_CONFIGURATION_REGISTERS]>,
29+
s: S,
30+
) -> Result<S::Ok, S::Error> {
31+
BigArray::serialize(val.as_ref(), s)
32+
}
33+
34+
pub fn deserialize<'de, D: Deserializer<'de>>(
35+
d: D,
36+
) -> Result<Box<[u32; NUM_CONFIGURATION_REGISTERS]>, D::Error> {
37+
BigArray::deserialize(d).map(Box::new)
38+
}
39+
}
40+
2141
const STATUS_REG: usize = 1;
2242
const STATUS_REG_CAPABILITIES_USED_MASK: u32 = 0x0010_0000;
2343
const BAR0_REG: u16 = 4;
@@ -64,12 +84,15 @@ struct PciBar {
6484
used: bool,
6585
}
6686

67-
/// PCI configuration space state for (de)serialization
87+
/// PCI configuration space state for (de)serialization.
88+
/// Register arrays are boxed to prevent stack overflow during (de)serialization.
6889
#[derive(Debug, Clone, Serialize, Deserialize)]
6990
pub struct PciConfigurationState {
70-
registers: Vec<u32>,
71-
writable_bits: Vec<u32>,
72-
bars: Vec<PciBar>,
91+
#[serde(with = "boxed_big_array")]
92+
registers: Box<[u32; NUM_CONFIGURATION_REGISTERS]>,
93+
#[serde(with = "boxed_big_array")]
94+
writable_bits: Box<[u32; NUM_CONFIGURATION_REGISTERS]>,
95+
bars: [PciBar; NUM_BAR_REGS],
7396
last_capability: Option<(u8, u8)>,
7497
msix_cap_reg_idx: Option<u16>,
7598
}
@@ -131,9 +154,9 @@ impl PciConfiguration {
131154
msix_config: Option<Arc<Mutex<MsixConfig>>>,
132155
) -> Self {
133156
PciConfiguration {
134-
registers: state.registers.try_into().unwrap(),
135-
writable_bits: state.writable_bits.try_into().unwrap(),
136-
bars: state.bars.try_into().unwrap(),
157+
registers: *state.registers,
158+
writable_bits: *state.writable_bits,
159+
bars: state.bars,
137160
last_capability: state.last_capability,
138161
msix_cap_reg_idx: state.msix_cap_reg_idx,
139162
msix_config,
@@ -143,9 +166,9 @@ impl PciConfiguration {
143166
/// Create PCI configuration space state
144167
pub fn state(&self) -> PciConfigurationState {
145168
PciConfigurationState {
146-
registers: self.registers.to_vec(),
147-
writable_bits: self.writable_bits.to_vec(),
148-
bars: self.bars.to_vec(),
169+
registers: Box::new(self.registers),
170+
writable_bits: Box::new(self.writable_bits),
171+
bars: self.bars,
149172
last_capability: self.last_capability,
150173
msix_cap_reg_idx: self.msix_cap_reg_idx,
151174
}

0 commit comments

Comments
 (0)