Skip to content

Commit 36ee540

Browse files
authored
read: use address size when checking address overflow (gimli-rs#733)
Also, validate address sizes when reading them so that the address mask calculation is correct.
1 parent 38c185e commit 36ee540

File tree

8 files changed

+157
-48
lines changed

8 files changed

+157
-48
lines changed

src/read/aranges.rs

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use crate::common::{DebugArangesOffset, DebugInfoOffset, Encoding, SectionId};
22
use crate::endianity::Endianity;
3-
use crate::read::{EndianSlice, Error, Range, Reader, ReaderOffset, Result, Section};
3+
use crate::read::{
4+
EndianSlice, Error, Range, Reader, ReaderAddress, ReaderOffset, Result, Section,
5+
};
46

57
/// The `DebugAranges` struct represents the DWARF address range information
68
/// found in the `.debug_aranges` section.
@@ -157,7 +159,7 @@ where
157159
}
158160

159161
let debug_info_offset = rest.read_offset(format).map(DebugInfoOffset)?;
160-
let address_size = rest.read_u8()?;
162+
let address_size = rest.read_address_size()?;
161163
let segment_size = rest.read_u8()?;
162164
if segment_size != 0 {
163165
return Err(Error::UnsupportedSegmentSize);
@@ -170,9 +172,9 @@ where
170172
// a multiple of the size of a single tuple (that is, twice the size of an address).
171173
let tuple_length = address_size
172174
.checked_mul(2)
173-
.ok_or(Error::InvalidAddressRange)?;
175+
.ok_or(Error::UnsupportedAddressSize(address_size))?;
174176
if tuple_length == 0 {
175-
return Err(Error::InvalidAddressRange);
177+
return Err(Error::UnsupportedAddressSize(address_size));
176178
}
177179
let padding = if header_length % tuple_length == 0 {
178180
0
@@ -296,8 +298,7 @@ impl ArangeEntry {
296298
let begin = input.read_address(address_size)?;
297299
let length = input.read_address(address_size)?;
298300
// Calculate end now so that we can handle overflow.
299-
// TODO: handle 32-bit address overflow as well.
300-
let end = begin.checked_add(length).ok_or(Error::AddressOverflow)?;
301+
let end = begin.add_sized(length, address_size)?;
301302
let range = Range { begin, end };
302303

303304
match (begin, length) {
@@ -481,7 +482,7 @@ mod tests {
481482

482483
let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10))
483484
.expect_err("should fail to parse header");
484-
assert_eq!(error, Error::InvalidAddressRange);
485+
assert_eq!(error, Error::UnsupportedAddressSize(0xff));
485486
}
486487

487488
#[test]
@@ -521,7 +522,7 @@ mod tests {
521522

522523
let error = ArangeHeader::parse(rest, DebugArangesOffset(0x10))
523524
.expect_err("should fail to parse header");
524-
assert_eq!(error, Error::InvalidAddressRange);
525+
assert_eq!(error, Error::UnsupportedAddressSize(0));
525526
}
526527

527528
#[test]
@@ -581,7 +582,29 @@ mod tests {
581582
}
582583

583584
#[test]
584-
fn test_parse_entry_overflow() {
585+
fn test_parse_entry_overflow_32() {
586+
let encoding = Encoding {
587+
format: Format::Dwarf32,
588+
version: 2,
589+
address_size: 4,
590+
};
591+
#[rustfmt::skip]
592+
let buf = [
593+
// Address.
594+
0x01, 0x02, 0x03, 0x84,
595+
// Length.
596+
0x05, 0x06, 0x07, 0x88,
597+
// Next tuple.
598+
0x09
599+
];
600+
let rest = &mut EndianSlice::new(&buf, LittleEndian);
601+
let entry = ArangeEntry::parse(rest, encoding);
602+
assert_eq!(*rest, EndianSlice::new(&buf[buf.len() - 1..], LittleEndian));
603+
assert_eq!(entry, Err(Error::AddressOverflow));
604+
}
605+
606+
#[test]
607+
fn test_parse_entry_overflow_64() {
585608
let encoding = Encoding {
586609
format: Format::Dwarf32,
587610
version: 2,

src/read/cfi.rs

Lines changed: 35 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ use crate::common::{
1414
use crate::constants::{self, DwEhPe};
1515
use crate::endianity::Endianity;
1616
use crate::read::{
17-
EndianSlice, Error, Expression, Reader, ReaderOffset, Result, Section, StoreOnHeap,
17+
EndianSlice, Error, Expression, Reader, ReaderAddress, ReaderOffset, Result, Section,
18+
StoreOnHeap,
1819
};
1920

2021
/// `DebugFrame` contains the `.debug_frame` section's frame unwinding
@@ -1341,7 +1342,7 @@ impl<R: Reader> CommonInformationEntry<R> {
13411342
let mut augmentation_string = rest.read_null_terminated_slice()?;
13421343

13431344
let address_size = if Section::has_address_and_segment_sizes(version) {
1344-
let address_size = rest.read_u8()?;
1345+
let address_size = rest.read_address_size()?;
13451346
let segment_size = rest.read_u8()?;
13461347
if segment_size != 0 {
13471348
return Err(Error::UnsupportedSegmentSize);
@@ -1805,7 +1806,8 @@ impl<R: Reader> FrameDescriptionEntry<R> {
18051806
/// This uses wrapping arithmetic, so the result may be less than
18061807
/// `initial_address`.
18071808
pub fn end_address(&self) -> u64 {
1808-
self.initial_address.wrapping_add(self.address_range)
1809+
self.initial_address
1810+
.wrapping_add_sized(self.address_range, self.cie.address_size)
18091811
}
18101812

18111813
/// The number of bytes of instructions that this entry has unwind
@@ -2198,6 +2200,7 @@ where
21982200
{
21992201
code_alignment_factor: Wrapping<u64>,
22002202
data_alignment_factor: Wrapping<i64>,
2203+
address_size: u8,
22012204
next_start_address: u64,
22022205
last_end_address: u64,
22032206
returned_last_row: bool,
@@ -2237,6 +2240,7 @@ where
22372240
UnwindTable {
22382241
code_alignment_factor: Wrapping(fde.cie().code_alignment_factor()),
22392242
data_alignment_factor: Wrapping(fde.cie().data_alignment_factor()),
2243+
address_size: fde.cie().address_size,
22402244
next_start_address: fde.initial_address(),
22412245
last_end_address: fde.end_address(),
22422246
returned_last_row: false,
@@ -2256,6 +2260,7 @@ where
22562260
UnwindTable {
22572261
code_alignment_factor: Wrapping(cie.code_alignment_factor()),
22582262
data_alignment_factor: Wrapping(cie.data_alignment_factor()),
2263+
address_size: cie.address_size,
22592264
next_start_address: 0,
22602265
last_end_address: 0,
22612266
returned_last_row: false,
@@ -2330,13 +2335,10 @@ where
23302335
}
23312336
AdvanceLoc { delta } => {
23322337
let delta = Wrapping(u64::from(delta)) * self.code_alignment_factor;
2333-
let address = self
2338+
self.next_start_address = self
23342339
.ctx
23352340
.start_address()
2336-
.checked_add(delta.0)
2337-
.ok_or(Error::AddressOverflow)?;
2338-
2339-
self.next_start_address = address;
2341+
.add_sized(delta.0, self.address_size)?;
23402342
self.ctx.row_mut().end_address = self.next_start_address;
23412343
return Ok(true);
23422344
}
@@ -3651,7 +3653,8 @@ fn parse_encoded_pointer<R: Reader>(
36513653
constants::DW_EH_PE_pcrel => {
36523654
if let Some(section_base) = parameters.bases.section {
36533655
let offset_from_section = input.offset_from(parameters.section);
3654-
section_base.wrapping_add(offset_from_section.into_u64())
3656+
section_base
3657+
.wrapping_add_sized(offset_from_section.into_u64(), parameters.address_size)
36553658
} else {
36563659
return Err(Error::PcRelativePointerButSectionBaseIsUndefined);
36573660
}
@@ -3682,7 +3685,10 @@ fn parse_encoded_pointer<R: Reader>(
36823685
};
36833686

36843687
let offset = parse_encoded_value(encoding, parameters, input)?;
3685-
Ok(Pointer::new(encoding, base.wrapping_add(offset)))
3688+
Ok(Pointer::new(
3689+
encoding,
3690+
base.wrapping_add_sized(offset, parameters.address_size),
3691+
))
36863692
}
36873693

36883694
fn parse_encoded_value<R: Reader>(
@@ -5379,8 +5385,23 @@ mod tests {
53795385
}
53805386

53815387
#[test]
5382-
fn test_eval_advance_loc_overflow() {
5383-
let cie = make_test_cie();
5388+
fn test_eval_advance_loc_overflow_32() {
5389+
let mut cie = make_test_cie();
5390+
cie.address_size = 4;
5391+
let mut ctx = UnwindContext::new();
5392+
ctx.row_mut().start_address = u32::MAX.into();
5393+
let expected = ctx.clone();
5394+
let instructions = [(
5395+
Err(Error::AddressOverflow),
5396+
CallFrameInstruction::AdvanceLoc { delta: 42 },
5397+
)];
5398+
assert_eval(ctx, expected, cie, None, instructions);
5399+
}
5400+
5401+
#[test]
5402+
fn test_eval_advance_loc_overflow_64() {
5403+
let mut cie = make_test_cie();
5404+
cie.address_size = 8;
53845405
let mut ctx = UnwindContext::new();
53855406
ctx.row_mut().start_address = u64::MAX;
53865407
let expected = ctx.clone();
@@ -7676,7 +7697,7 @@ mod tests {
76767697
let parameters = PointerEncodingParameters {
76777698
bases: &SectionBaseAddresses::default(),
76787699
func_base: None,
7679-
address_size: 4,
7700+
address_size: 8,
76807701
section: &input,
76817702
};
76827703
assert_eq!(
@@ -7779,7 +7800,7 @@ mod tests {
77797800
let parameters = PointerEncodingParameters {
77807801
bases: &SectionBaseAddresses::default(),
77817802
func_base: None,
7782-
address_size: 4,
7803+
address_size: 8,
77837804
section: &input,
77847805
};
77857806
assert_eq!(

src/read/line.rs

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ use crate::common::{
99
};
1010
use crate::constants;
1111
use crate::endianity::Endianity;
12-
use crate::read::{AttributeValue, EndianSlice, Error, Reader, ReaderOffset, Result, Section};
12+
use crate::read::{
13+
AttributeValue, EndianSlice, Error, Reader, ReaderAddress, ReaderOffset, Result, Section,
14+
};
1315

1416
/// The `DebugLine` struct contains the source location to instruction mapping
1517
/// found in the `.debug_line` section.
@@ -852,10 +854,8 @@ impl LineRow {
852854

853855
LineInstruction::FixedAddPc(operand) => {
854856
if !self.tombstone {
855-
self.address = self
856-
.address
857-
.checked_add(u64::from(operand))
858-
.ok_or(Error::AddressOverflow)?;
857+
let address_size = program.header().address_size();
858+
self.address = self.address.add_sized(u64::from(operand), address_size)?;
859859
self.op_index.0 = 0;
860860
}
861861
false
@@ -975,8 +975,7 @@ impl LineRow {
975975
};
976976
self.address = self
977977
.address
978-
.checked_add(address_advance.0)
979-
.ok_or(Error::AddressOverflow)?;
978+
.add_sized(address_advance.0, header.address_size())?;
980979
Ok(())
981980
}
982981

@@ -1324,7 +1323,7 @@ where
13241323
}
13251324

13261325
if version >= 5 {
1327-
address_size = rest.read_u8()?;
1326+
address_size = rest.read_address_size()?;
13281327
let segment_selector_size = rest.read_u8()?;
13291328
if segment_selector_size != 0 {
13301329
return Err(Error::UnsupportedSegmentSize);
@@ -2639,8 +2638,21 @@ mod tests {
26392638
}
26402639

26412640
#[test]
2642-
fn test_exec_advance_pc_overflow() {
2643-
let header = make_test_header(EndianSlice::new(&[], LittleEndian));
2641+
fn test_exec_advance_pc_overflow_32() {
2642+
let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2643+
header.encoding.address_size = 4;
2644+
let mut registers = LineRow::new(&header);
2645+
registers.address = u32::MAX.into();
2646+
let opcode = LineInstruction::AdvancePc(42);
2647+
let mut program = IncompleteLineProgram { header };
2648+
let result = registers.execute(opcode, &mut program);
2649+
assert_eq!(result, Err(Error::AddressOverflow));
2650+
}
2651+
2652+
#[test]
2653+
fn test_exec_advance_pc_overflow_64() {
2654+
let mut header = make_test_header(EndianSlice::new(&[], LittleEndian));
2655+
header.encoding.address_size = 8;
26442656
let mut registers = LineRow::new(&header);
26452657
registers.address = u64::MAX;
26462658
let opcode = LineInstruction::AdvancePc(42);

src/read/lists.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ fn parse_header<R: Reader>(input: &mut R) -> Result<ListsHeader> {
4949
return Err(Error::UnknownVersion(u64::from(version)));
5050
}
5151

52-
let address_size = input.read_u8()?;
52+
let address_size = input.read_address_size()?;
5353
let segment_selector_size = input.read_u8()?;
5454
if segment_selector_size != 0 {
5555
return Err(Error::UnsupportedSegmentSize);

src/read/loclists.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ use crate::constants;
66
use crate::endianity::Endianity;
77
use crate::read::{
88
lists::ListsHeader, DebugAddr, EndianSlice, Error, Expression, Range, RawRange, Reader,
9-
ReaderOffset, ReaderOffsetId, Result, Section,
9+
ReaderAddress, ReaderOffset, ReaderOffsetId, Result, Section,
1010
};
1111

1212
/// The raw contents of the `.debug_loc` section.
@@ -593,7 +593,8 @@ impl<R: Reader> LocListIter<R> {
593593
&mut self,
594594
raw_loc: RawLocListEntry<R>,
595595
) -> Result<Option<LocationListEntry<R>>> {
596-
let mask = !0 >> (64 - self.raw.encoding.address_size * 8);
596+
let address_size = self.raw.encoding.address_size;
597+
let mask = u64::ones_sized(address_size);
597598
let tombstone = if self.raw.encoding.version <= 4 {
598599
mask - 1
599600
} else {
@@ -620,7 +621,7 @@ impl<R: Reader> LocListIter<R> {
620621
data,
621622
} => {
622623
let begin = self.get_address(begin)?;
623-
let end = begin.wrapping_add(length) & mask;
624+
let end = begin.wrapping_add_sized(length, address_size);
624625
(Range { begin, end }, data)
625626
}
626627
RawLocListEntry::DefaultLocation { data } => (
@@ -645,7 +646,7 @@ impl<R: Reader> LocListIter<R> {
645646
length,
646647
data,
647648
} => {
648-
let end = begin.wrapping_add(length) & mask;
649+
let end = begin.wrapping_add_sized(length, address_size);
649650
(Range { begin, end }, data)
650651
}
651652
};

0 commit comments

Comments
 (0)