1 // Defined note types for GNU systems. 2 3 #[cfg(feature = "log")] 4 use log::debug; 5 #[cfg(feature = "alloc")] 6 use scroll::{Pread, Pwrite, IOread, IOwrite, SizeWith}; 7 8 /// ABI information. 9 /// 10 /// The descriptor consists of words: 11 /// * word 0: OS descriptor 12 /// * word 1: major version of the ABI 13 /// * word 2: minor version of the ABI 14 /// * word 3: subminor version of the ABI 15 pub const NT_GNU_ABI_TAG: u32 = 1; 16 17 /// Old name 18 pub const ELF_NOTE_ABI: u32 = NT_GNU_ABI_TAG; 19 // Known OSes. These values can appear in word 0 of an 20 // `NT_GNU_ABI_TAG` note section entry. 21 pub const ELF_NOTE_OS_LINUX: u32 = 0; 22 pub const ELF_NOTE_OS_GNU: u32 = 1; 23 pub const ELF_NOTE_OS_SOLARIS2: u32 = 2; 24 pub const ELF_NOTE_OS_FREEBSD: u32 = 3; 25 26 /// Synthetic `hwcap` information. 27 /// 28 /// The descriptor begins with two words: 29 /// * word 0: number of entries 30 /// * word 1: bitmask of enabled entries 31 /// 32 /// Then follow variable-length entries, one byte followed by a '\0'-terminated 33 /// `hwcap` name string. The byte gives the bit number to test if enabled, 34 /// `(1U << bit) & bitmask`. 35 pub const NT_GNU_HWCAP: u32 = 2; 36 37 /// Build ID bits as generated by ld --build-id. 38 /// 39 /// The descriptor consists of any nonzero number of bytes. 40 pub const NT_GNU_BUILD_ID: u32 = 3; 41 42 /// Version note generated by GNU gold containing a version string. 43 pub const NT_GNU_GOLD_VERSION: u32 = 4; 44 45 #[derive(Clone, Copy, Debug)] 46 #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] 47 #[repr(C)] 48 /// Note section contents. Each entry in the note section begins with a header 49 /// of a fixed form. 50 pub struct Nhdr32 { 51 /// Length of the note's name (includes the terminator) 52 pub n_namesz: u32, 53 /// Length of the note's descriptor 54 pub n_descsz: u32, 55 /// Type of the note 56 pub n_type: u32, 57 } 58 59 #[derive(Clone, Copy, Debug)] 60 #[cfg_attr(feature = "alloc", derive(Pread, Pwrite, IOread, IOwrite, SizeWith))] 61 #[repr(C)] 62 /// Note section contents. Each entry in the note section begins with a header 63 /// of a fixed form. 64 pub struct Nhdr64 { 65 /// Length of the note's name (includes the terminator) 66 pub n_namesz: u64, 67 /// Length of the note's descriptor. 68 pub n_descsz: u64, 69 /// Type of the note. 70 pub n_type: u64, 71 } 72 73 if_alloc! { 74 use crate::error; 75 use crate::container; 76 use scroll::ctx; 77 use alloc::vec::Vec; 78 79 /// An iterator over ELF binary notes in a note section or segment 80 pub struct NoteDataIterator<'a> { 81 pub data: &'a [u8], 82 pub size: usize, 83 pub offset: usize, 84 pub ctx: (usize, container::Ctx), // (alignment, ctx) 85 } 86 87 impl<'a> Iterator for NoteDataIterator<'a> { 88 type Item = error::Result<Note<'a>>; 89 fn next(&mut self) -> Option<Self::Item> { 90 if self.offset >= self.size { 91 None 92 } else { 93 debug!("NoteIterator - {:#x}", self.offset); 94 match self.data.gread_with(&mut self.offset, self.ctx) { 95 Ok(res) => Some(Ok(res)), 96 Err(e) => Some(Err(e)) 97 } 98 } 99 } 100 } 101 102 /// An iterator over ELF binary notes 103 pub struct NoteIterator<'a> { 104 pub iters: Vec<NoteDataIterator<'a>>, 105 pub index: usize, 106 } 107 108 impl<'a> Iterator for NoteIterator<'a> { 109 type Item = error::Result<Note<'a>>; 110 fn next(&mut self) -> Option<Self::Item> { 111 while self.index < self.iters.len() { 112 if let Some(note_result) = self.iters[self.index].next() { 113 return Some(note_result); 114 } 115 116 self.index += 1; 117 } 118 119 None 120 } 121 } 122 123 #[derive(Debug)] 124 struct NoteHeader { 125 n_namesz: usize, 126 n_descsz: usize, 127 n_type: u32, 128 } 129 130 impl From<Nhdr32> for NoteHeader { 131 fn from(header: Nhdr32) -> Self { 132 NoteHeader { 133 n_namesz: header.n_namesz as usize, 134 n_descsz: header.n_descsz as usize, 135 n_type: header.n_type, 136 } 137 } 138 } 139 140 impl From<Nhdr64> for NoteHeader { 141 fn from(header: Nhdr64) -> Self { 142 NoteHeader { 143 n_namesz: header.n_namesz as usize, 144 n_descsz: header.n_descsz as usize, 145 n_type: header.n_type as u32, 146 } 147 } 148 } 149 150 fn align(alignment: usize, offset: &mut usize) { 151 let diff = *offset % alignment; 152 if diff != 0 { 153 *offset += alignment - diff; 154 } 155 } 156 157 /// A 32/64 bit Note struct, with the name and desc pre-parsed 158 #[derive(Debug)] 159 pub struct Note<'a> { 160 /// The type of this note 161 pub n_type: u32, 162 /// NUL terminated string, where `namesz` includes the terminator 163 pub name: &'a str, // needs padding such that namesz + padding % {wordsize} == 0 164 /// arbitrary data of length `descsz` 165 pub desc: &'a [u8], // needs padding such that descsz + padding % {wordsize} == 0 166 } 167 168 impl<'a> Note<'a> { 169 pub fn type_to_str(&self) -> &'static str { 170 match self.n_type { 171 NT_GNU_ABI_TAG => "NT_GNU_ABI_TAG", 172 NT_GNU_HWCAP => "NT_GNU_HWCAP", 173 NT_GNU_BUILD_ID => "NT_GNU_BUILD_ID", 174 NT_GNU_GOLD_VERSION => "NT_GNU_GOLD_VERSION", 175 _ => "NT_UNKNOWN" 176 } 177 } 178 } 179 180 impl<'a> ctx::TryFromCtx<'a, (usize, container::Ctx)> for Note<'a> { 181 type Error = error::Error; 182 fn try_from_ctx(bytes: &'a [u8], (alignment, ctx): (usize, container::Ctx)) -> Result<(Self, usize), Self::Error> { 183 let offset = &mut 0; 184 let mut alignment = alignment; 185 if alignment < 4 { 186 alignment = 4; 187 } 188 let header: NoteHeader = { 189 match alignment { 190 4|8 => bytes.gread_with::<Nhdr32>(offset, ctx.le)?.into(), 191 _ => return Err(error::Error::Malformed(format!("Notes has unimplemented alignment requirement: {:#x}", alignment))) 192 } 193 }; 194 debug!("{:?} - {:#x}", header, *offset); 195 // -1 because includes \0 terminator 196 let name = bytes.gread_with::<&'a str>(offset, ctx::StrCtx::Length(header.n_namesz - 1))?; 197 *offset += 1; 198 align(alignment, offset); 199 debug!("note name {} - {:#x}", name, *offset); 200 let desc = bytes.gread_with::<&'a [u8]>(offset, header.n_descsz)?; 201 align(alignment, offset); 202 debug!("desc {:?} - {:#x}", desc, *offset); 203 Ok((Note { 204 name, 205 desc, 206 n_type: header.n_type, 207 }, *offset)) 208 } 209 } 210 211 #[cfg(test)] 212 mod tests { 213 use super::*; 214 215 static NOTE_DATA: [u8; 68] = [0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 216 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 217 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 218 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 219 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 220 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 221 0xbc, 0xfc, 0x66, 0xcd, 0xc7, 0xd5, 0x14, 0x7b, 222 0x53, 0xb1, 0x10, 0x11, 0x94, 0x86, 0x8e, 0xf9, 223 0x4f, 0xe8, 0xdd, 0xdb]; 224 225 static CONTEXT: (usize, container::Ctx) = (4, container::Ctx { 226 container: container::Container::Big, 227 le: ::scroll::Endian::Little, 228 }); 229 230 fn make_note_iter(start: usize, end: usize) -> NoteDataIterator<'static> { 231 NoteDataIterator { 232 data: &NOTE_DATA, 233 size: end, 234 offset: start, 235 ctx: CONTEXT, 236 } 237 } 238 239 #[test] 240 fn iter_single_section() { 241 let mut notes = NoteIterator { 242 iters: vec![make_note_iter(0, 68)], 243 index: 0, 244 }; 245 246 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); 247 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); 248 assert!(notes.next().is_none()); 249 } 250 251 #[test] 252 fn iter_multiple_sections() { 253 let mut notes = NoteIterator { 254 iters: vec![make_note_iter(0, 32), make_note_iter(32, 68)], 255 index: 0, 256 }; 257 258 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); 259 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); 260 assert!(notes.next().is_none()); 261 } 262 263 #[test] 264 fn skip_empty_sections() { 265 let mut notes = NoteIterator { 266 iters: vec![ 267 make_note_iter(0, 32), 268 make_note_iter(0, 0), 269 make_note_iter(32, 68), 270 ], 271 index: 0, 272 }; 273 274 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); 275 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); 276 assert!(notes.next().is_none()); 277 } 278 279 #[test] 280 fn ignore_no_sections() { 281 let mut notes = NoteIterator { iters: vec![], index: 0 }; 282 assert!(notes.next().is_none()); 283 } 284 } 285 } 286