Skip to content

Commit 74c757c

Browse files
authored
read/macho: fix data for segments in dyld caches (#673)
Use the correct subcache for operations on the segment itself. Individual section data was already using the correct subcache. This also does the change for section relocations, but they shouldn't be present in the dyld cache.
1 parent 9650d64 commit 74c757c

File tree

3 files changed

+24
-32
lines changed

3 files changed

+24
-32
lines changed

Diff for: src/read/macho/file.rs

+5-15
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ where
4444
pub(super) header_offset: u64,
4545
pub(super) header: &'data Mach,
4646
pub(super) segments: Vec<MachOSegmentInternal<'data, Mach, R>>,
47-
pub(super) sections: Vec<MachOSectionInternal<'data, Mach>>,
47+
pub(super) sections: Vec<MachOSectionInternal<'data, Mach, R>>,
4848
pub(super) symbols: SymbolTable<'data, Mach, R>,
4949
}
5050

@@ -65,11 +65,10 @@ where
6565
if let Ok(mut commands) = header.load_commands(endian, data, 0) {
6666
while let Ok(Some(command)) = commands.next() {
6767
if let Some((segment, section_data)) = Mach::Segment::from_command(command)? {
68-
let segment_index = segments.len();
6968
segments.push(MachOSegmentInternal { segment, data });
7069
for section in segment.sections(endian, section_data)? {
7170
let index = SectionIndex(sections.len() + 1);
72-
sections.push(MachOSectionInternal::parse(index, segment_index, section));
71+
sections.push(MachOSectionInternal::parse(index, section, data));
7372
}
7473
} else if let Some(symtab) = command.symtab()? {
7574
symbols = symtab.symbols(endian, data)?;
@@ -110,6 +109,7 @@ where
110109
if let Some((segment, section_data)) = Mach::Segment::from_command(command)? {
111110
// Each segment can be stored in a different subcache. Get the segment's
112111
// address and look it up in the cache mappings, to find the correct cache data.
112+
// This was observed for the arm64e __LINKEDIT segment in macOS 12.0.1.
113113
let addr = segment.vmaddr(endian).into();
114114
let (data, _offset) = image
115115
.cache
@@ -118,12 +118,11 @@ where
118118
if segment.name() == macho::SEG_LINKEDIT.as_bytes() {
119119
linkedit_data = Some(data);
120120
}
121-
let segment_index = segments.len();
122121
segments.push(MachOSegmentInternal { segment, data });
123122

124123
for section in segment.sections(endian, section_data)? {
125124
let index = SectionIndex(sections.len() + 1);
126-
sections.push(MachOSectionInternal::parse(index, segment_index, section));
125+
sections.push(MachOSectionInternal::parse(index, section, data));
127126
}
128127
} else if let Some(st) = command.symtab()? {
129128
symtab = Some(st);
@@ -154,23 +153,14 @@ where
154153
pub(super) fn section_internal(
155154
&self,
156155
index: SectionIndex,
157-
) -> Result<&MachOSectionInternal<'data, Mach>> {
156+
) -> Result<&MachOSectionInternal<'data, Mach, R>> {
158157
index
159158
.0
160159
.checked_sub(1)
161160
.and_then(|index| self.sections.get(index))
162161
.read_error("Invalid Mach-O section index")
163162
}
164163

165-
pub(super) fn segment_internal(
166-
&self,
167-
index: usize,
168-
) -> Result<&MachOSegmentInternal<'data, Mach, R>> {
169-
self.segments
170-
.get(index)
171-
.read_error("Invalid Mach-O segment index")
172-
}
173-
174164
/// Returns the endianness.
175165
pub fn endian(&self) -> Mach::Endian {
176166
self.endian

Diff for: src/read/macho/section.rs

+13-15
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ where
2525
R: ReadRef<'data>,
2626
{
2727
pub(super) file: &'file MachOFile<'data, Mach, R>,
28-
pub(super) iter: slice::Iter<'file, MachOSectionInternal<'data, Mach>>,
28+
pub(super) iter: slice::Iter<'file, MachOSectionInternal<'data, Mach, R>>,
2929
}
3030

3131
impl<'data, 'file, Mach, R> fmt::Debug for MachOSectionIterator<'data, 'file, Mach, R>
@@ -71,7 +71,7 @@ where
7171
R: ReadRef<'data>,
7272
{
7373
pub(super) file: &'file MachOFile<'data, Mach, R>,
74-
pub(super) internal: MachOSectionInternal<'data, Mach>,
74+
pub(super) internal: MachOSectionInternal<'data, Mach, R>,
7575
}
7676

7777
impl<'data, 'file, Mach, R> MachOSection<'data, 'file, Mach, R>
@@ -80,11 +80,9 @@ where
8080
R: ReadRef<'data>,
8181
{
8282
fn bytes(&self) -> Result<&'data [u8]> {
83-
let segment_index = self.internal.segment_index;
84-
let segment = self.file.segment_internal(segment_index)?;
8583
self.internal
8684
.section
87-
.data(self.file.endian, segment.data)
85+
.data(self.file.endian, self.internal.data)
8886
.read_error("Invalid Mach-O section size or offset")
8987
}
9088
}
@@ -193,7 +191,7 @@ where
193191
relocations: self
194192
.internal
195193
.section
196-
.relocations(self.file.endian, self.file.data)
194+
.relocations(self.file.endian, self.internal.data)
197195
.unwrap_or(&[])
198196
.iter(),
199197
}
@@ -211,19 +209,19 @@ where
211209
}
212210

213211
#[derive(Debug, Clone, Copy)]
214-
pub(super) struct MachOSectionInternal<'data, Mach: MachHeader> {
212+
pub(super) struct MachOSectionInternal<'data, Mach: MachHeader, R: ReadRef<'data>> {
215213
pub index: SectionIndex,
216-
pub segment_index: usize,
217214
pub kind: SectionKind,
218215
pub section: &'data Mach::Section,
216+
/// The data for the file that contains the section data.
217+
///
218+
/// This is required for dyld caches, where this may be a different subcache
219+
/// from the file containing the Mach-O load commands.
220+
pub data: R,
219221
}
220222

221-
impl<'data, Mach: MachHeader> MachOSectionInternal<'data, Mach> {
222-
pub(super) fn parse(
223-
index: SectionIndex,
224-
segment_index: usize,
225-
section: &'data Mach::Section,
226-
) -> Self {
223+
impl<'data, Mach: MachHeader, R: ReadRef<'data>> MachOSectionInternal<'data, Mach, R> {
224+
pub(super) fn parse(index: SectionIndex, section: &'data Mach::Section, data: R) -> Self {
227225
// TODO: we don't validate flags, should we?
228226
let kind = match (section.segment_name(), section.name()) {
229227
(b"__TEXT", b"__text") => SectionKind::Text,
@@ -246,9 +244,9 @@ impl<'data, Mach: MachHeader> MachOSectionInternal<'data, Mach> {
246244
};
247245
MachOSectionInternal {
248246
index,
249-
segment_index,
250247
kind,
251248
section,
249+
data,
252250
}
253251
}
254252
}

Diff for: src/read/macho/segment.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ where
6969
fn bytes(&self) -> Result<&'data [u8]> {
7070
self.internal
7171
.segment
72-
.data(self.file.endian, self.file.data)
72+
.data(self.file.endian, self.internal.data)
7373
.read_error("Invalid Mach-O segment size or offset")
7474
}
7575
}
@@ -149,8 +149,12 @@ where
149149

150150
#[derive(Debug, Clone, Copy)]
151151
pub(super) struct MachOSegmentInternal<'data, Mach: MachHeader, R: ReadRef<'data>> {
152-
pub data: R,
153152
pub segment: &'data Mach::Segment,
153+
/// The data for the file that contains the segment data.
154+
///
155+
/// This is required for dyld caches, where this may be a different subcache
156+
/// from the file containing the Mach-O load commands.
157+
pub data: R,
154158
}
155159

156160
/// A trait for generic access to [`macho::SegmentCommand32`] and [`macho::SegmentCommand64`].

0 commit comments

Comments
 (0)