Skip to content

Commit a3b0dd9

Browse files
committed
chroe: properly perform checksums on partition table arrays
Some partitioning tools like ones based on libparted (parted and GParted) don't wipe the entire GPT partition name field before writing new partition names. Additionally, it is not guaranteed to be properly zeroed since the UEFI specification does not clearly state that. Use a dedicated raw buffer holding the entire partition name field without any conversion for performing checksums and serializations. Signed-off-by: Xinhui Yang <[email protected]>
1 parent 7bd1432 commit a3b0dd9

File tree

1 file changed

+37
-16
lines changed

1 file changed

+37
-16
lines changed

src/lib.rs

Lines changed: 37 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -378,24 +378,35 @@ impl GPTHeader {
378378

379379
/// A wrapper type for `String` that represents a partition's name.
380380
#[derive(Debug, Clone, PartialEq, Eq)]
381-
pub struct PartitionName(String);
381+
pub struct PartitionName {
382+
string: String,
383+
raw_buf: [u8; 72],
384+
}
382385

383386
impl PartitionName {
384387
/// Extracts a string slice containing the entire `PartitionName`.
385388
pub fn as_str(&self) -> &str {
386-
self.0.as_str()
389+
&self.string
387390
}
388391
}
389392

390393
impl std::fmt::Display for PartitionName {
391394
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
392-
write!(f, "{}", self.0)
395+
write!(f, "{}", &self.string)
393396
}
394397
}
395398

396399
impl From<&str> for PartitionName {
397400
fn from(value: &str) -> PartitionName {
398-
PartitionName(value.to_string())
401+
let utf16_converted = value.encode_utf16();
402+
let mut raw_buf = [0; 72];
403+
for (idx, chr) in utf16_converted.into_iter().take(36).enumerate() {
404+
raw_buf[idx * 2..=idx * 2 + 1].copy_from_slice(&chr.to_le_bytes());
405+
}
406+
PartitionName {
407+
string: value.to_string(),
408+
raw_buf,
409+
}
399410
}
400411
}
401412

@@ -412,18 +423,28 @@ impl<'de> Visitor<'de> for UTF16LEVisitor {
412423
where
413424
A: SeqAccess<'de>,
414425
{
415-
let mut v = Vec::new();
426+
let mut v: Vec<u16> = Vec::new();
427+
let mut raw_buf = [0; 72];
416428
let mut end = false;
417-
loop {
418-
match seq.next_element()? {
419-
Some(0) => end = true,
420-
Some(x) if !end => v.push(x),
421-
Some(_) => {}
422-
None => break,
429+
let mut idx = 0;
430+
while let Some(x) = seq.next_element()? {
431+
if idx >= 72 {
432+
break;
433+
}
434+
if x == 0 {
435+
end = true;
436+
}
437+
if !end {
438+
v.push(x);
423439
}
424-
}
425440

426-
Ok(PartitionName(String::from_utf16_lossy(&v)))
441+
raw_buf[idx..=idx + 1].copy_from_slice(&x.to_le_bytes());
442+
idx += 2;
443+
}
444+
Ok(PartitionName {
445+
string: String::from_utf16_lossy(&v),
446+
raw_buf,
447+
})
427448
}
428449
}
429450

@@ -441,9 +462,9 @@ impl Serialize for PartitionName {
441462
where
442463
S: Serializer,
443464
{
444-
let s = self.0.encode_utf16();
445-
let mut seq = serializer.serialize_tuple(36)?;
446-
for x in s.chain([0].iter().cycle().cloned()).take(36) {
465+
// Favor using the content in the raw buffer in case there is garbage left (used for the CRC)
466+
let mut seq = serializer.serialize_tuple(72)?;
467+
for x in self.raw_buf {
447468
seq.serialize_element(&x)?;
448469
}
449470
seq.end()

0 commit comments

Comments
 (0)