Skip to main content

lime_rs/
lib.rs

1//! LiME dump parser
2//!
3//! This crate provides Rust structures for parsing LiME (Linux Memory Extractor) dump files.
4//! The LiME dump format is widely used by memory acquisition tools including:
5//! - [LiME](https://github.com/504ensicsLabs/LiME) - Linux Memory Extractor
6//! - [AVML](https://github.com/microsoft/avml) - AVML - Acquire Volatile Memory for Linux
7//! - [LEMON](https://github.com/eurecom-s3/lemon) - eBPF Memory Dump Tool
8//!
9//! The implementation is built on top of the [binrw](https://crates.io/crates/binrw) crate.
10
11pub use binrw::BinRead;
12
13/// Header defined by the `LiME` file format, version 1
14///
15/// source: [LiME Memory Range Header Version 1 Specification](https://github.com/504ensicsLabs/LiME/blob/master/doc/README.md#Spec)
16#[derive(Debug, BinRead)]
17#[br(little, magic = 0x4C69_4D45_u32)] //LiME
18pub struct LimeHeader {
19    /// Header version number
20    pub version: u32,
21    /// Starting address of physical RAM range
22    pub s_addr: u64,
23    /// Ending address of physical RAM range
24    #[br(assert(e_addr >= s_addr, "End address can not be lower than start address"))]
25    pub e_addr: u64,
26    /// Currently all zeros
27    pub reserved: [u8; 8],
28}
29
30impl LimeHeader {
31    /// Size in bytes of the memory represented by this header
32    pub const fn payload_size(&self) -> u64 {
33        self.e_addr - self.s_addr + 1
34    }
35}
36
37#[cfg(test)]
38mod tests {
39    use super::*;
40    use binrw::Error;
41    use std::io::Cursor;
42
43    #[test]
44    fn header_size() {
45        assert_eq!(size_of::<LimeHeader>(), 32);
46    }
47
48    #[test]
49    fn header_parser_works() {
50        let raw_header: [u8; size_of::<LimeHeader>()] = [
51            0x45, 0x4d, 0x69, 0x4c, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0,
52            0xff, 0xff, 0xcf, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
53        ];
54        let mut cursor = Cursor::new(raw_header);
55        let header = LimeHeader::read(&mut cursor).unwrap();
56
57        assert_eq!(header.version, 1);
58        assert_eq!(header.s_addr, 0x40000000);
59        assert_eq!(header.e_addr, 0xFBD00000 - 1);
60        assert_eq!(header.reserved, [0; 8]);
61        assert_eq!(header.payload_size(), 0xFBD00000 - 0x40000000);
62    }
63
64    #[test]
65    fn bad_magic() {
66        let raw_header: [u8; size_of::<LimeHeader>()] = [
67            0xCA, 0xFE, 0xCA, 0xFE, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0x0,
68            0xff, 0xff, 0xcf, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
69        ];
70        let mut cursor = Cursor::new(raw_header);
71        assert!(matches!(
72            LimeHeader::read(&mut cursor),
73            Err(Error::BadMagic { .. })
74        ));
75    }
76
77    #[test]
78    fn negative_size() {
79        let raw_header: [u8; size_of::<LimeHeader>()] = [
80            0x45, 0x4d, 0x69, 0x4c, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x40, 0x0, 0x0, 0x0, 0xff,
81            0xff, 0xff, 0xcf, 0xfb, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
82        ];
83        let mut cursor = Cursor::new(raw_header);
84        assert!(matches!(
85            LimeHeader::read(&mut cursor),
86            Err(Error::AssertFail { .. })
87        ));
88    }
89}