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 crate::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 type Size = usize; 183 fn try_from_ctx(bytes: &'a [u8], (alignment, ctx): (usize, container::Ctx)) -> Result<(Self, Self::Size), Self::Error> { 184 let offset = &mut 0; 185 let mut alignment = alignment; 186 if alignment < 4 { 187 alignment = 4; 188 } 189 let header: NoteHeader = { 190 match alignment { 191 4|8 => bytes.gread_with::<Nhdr32>(offset, ctx.le)?.into(), 192 _ => return Err(error::Error::Malformed(format!("Notes has unimplemented alignment requirement: {:#x}", alignment))) 193 } 194 }; 195 debug!("{:?} - {:#x}", header, *offset); 196 // -1 because includes \0 terminator 197 let name = bytes.gread_with::<&'a str>(offset, ctx::StrCtx::Length(header.n_namesz - 1))?; 198 *offset += 1; 199 align(alignment, offset); 200 debug!("note name {} - {:#x}", name, *offset); 201 let desc = bytes.gread_with::<&'a [u8]>(offset, header.n_descsz)?; 202 align(alignment, offset); 203 debug!("desc {:?} - {:#x}", desc, *offset); 204 Ok((Note { 205 name, 206 desc, 207 n_type: header.n_type, 208 }, *offset)) 209 } 210 } 211 212 #[cfg(test)] 213 mod tests { 214 use super::*; 215 216 static NOTE_DATA: [u8; 68] = [0x04, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 217 0x01, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 218 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 219 0x06, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 220 0x04, 0x00, 0x00, 0x00, 0x14, 0x00, 0x00, 0x00, 221 0x03, 0x00, 0x00, 0x00, 0x47, 0x4e, 0x55, 0x00, 222 0xbc, 0xfc, 0x66, 0xcd, 0xc7, 0xd5, 0x14, 0x7b, 223 0x53, 0xb1, 0x10, 0x11, 0x94, 0x86, 0x8e, 0xf9, 224 0x4f, 0xe8, 0xdd, 0xdb]; 225 226 static CONTEXT: (usize, container::Ctx) = (4, container::Ctx { 227 container: container::Container::Big, 228 le: ::scroll::Endian::Little, 229 }); 230 231 fn make_note_iter(start: usize, end: usize) -> NoteDataIterator<'static> { 232 NoteDataIterator { 233 data: &NOTE_DATA, 234 size: end, 235 offset: start, 236 ctx: CONTEXT, 237 } 238 } 239 240 #[test] 241 fn iter_single_section() { 242 let mut notes = NoteIterator { 243 iters: vec![make_note_iter(0, 68)], 244 index: 0, 245 }; 246 247 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); 248 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); 249 assert!(notes.next().is_none()); 250 } 251 252 #[test] 253 fn iter_multiple_sections() { 254 let mut notes = NoteIterator { 255 iters: vec![make_note_iter(0, 32), make_note_iter(32, 68)], 256 index: 0, 257 }; 258 259 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); 260 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); 261 assert!(notes.next().is_none()); 262 } 263 264 #[test] 265 fn skip_empty_sections() { 266 let mut notes = NoteIterator { 267 iters: vec![ 268 make_note_iter(0, 32), 269 make_note_iter(0, 0), 270 make_note_iter(32, 68), 271 ], 272 index: 0, 273 }; 274 275 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_ABI_TAG); 276 assert_eq!(notes.next().unwrap().unwrap().n_type, NT_GNU_BUILD_ID); 277 assert!(notes.next().is_none()); 278 } 279 280 #[test] 281 fn ignore_no_sections() { 282 let mut notes = NoteIterator { iters: vec![], index: 0 }; 283 assert!(notes.next().is_none()); 284 } 285 } 286 } 287