Skip to main content

finch/platform/linux/
linux_.rs

1//! A basic model of the Linux Operating System.
2
3use crate::error::*;
4use crate::executor::Memory;
5use crate::platform::linux::{Constants, FileSystem, Whence};
6use falcon::il;
7use falcon::loader::{ElfLinker, Loader};
8use falcon::memory::MemoryPermissions;
9use log::trace;
10use std::path::PathBuf;
11
12const BRK_MAX_SIZE: u64 = 0x1000_0000;
13const MMAP_BASE: u64 = 0x6800_0000;
14
15const AT_FDCWD: u32 = 0xFFFF_FF9C;
16
17/// A basic model of the Linux Operating System.
18#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
19pub struct Linux {
20    // The base address of the program break.
21    brk_base: u64,
22    // The current program break.
23    brk_address: u64,
24    // A pointer to the constants defined for this platform in Linux
25    constants: &'static Constants,
26    // Our model of the file system.
27    file_system: FileSystem,
28    // The next address where an MMAP should allocate memory.
29    mmap_address: u64,
30}
31
32impl Linux {
33    /// Create a new basic model of the Linux Operating System.
34    pub fn new(
35        elf_linker: &ElfLinker,
36        base_path: Option<PathBuf>,
37        constants: &'static Constants,
38    ) -> Result<Linux> {
39        // We need to find the address after the "data" segment to start the
40        // program break... really just the highest address we can find
41        let backing = elf_linker.memory()?;
42
43        let mut address: u64 = 0;
44
45        for (section_address, section) in backing.sections() {
46            let high = section_address + section.len() as u64;
47            if high > address {
48                address = high;
49            }
50        }
51
52        trace!("brk set to 0x{:x}", address);
53
54        Ok(Linux {
55            brk_base: address,
56            brk_address: address,
57            constants,
58            file_system: FileSystem::new(base_path)?,
59            mmap_address: MMAP_BASE,
60        })
61    }
62
63    pub fn file_system(&self) -> &FileSystem {
64        &self.file_system
65    }
66
67    pub fn file_system_mut(&mut self) -> &mut FileSystem {
68        &mut self.file_system
69    }
70
71    // TODO: Do real posix file permissions
72    pub fn access(&self, path: &str, _mode: u64) -> u64 {
73        if self.file_system.exists(path) {
74            0
75        } else {
76            -1i64 as u64
77        }
78    }
79
80    pub fn brk(&mut self, address: u64, memory: &mut Memory) -> Result<u64> {
81        let result = if address < self.brk_address {
82            self.brk_address
83        } else if address - self.brk_base < BRK_MAX_SIZE {
84            let size = address - self.brk_base;
85            trace!(
86                "brk is mapping more memory address=0x{:x} size=0x{:x}",
87                self.brk_address,
88                size
89            );
90            memory.initialize_blank(self.brk_address, size)?;
91            self.brk_address = address;
92            address
93        } else {
94            self.brk_address
95        };
96        trace!("brk(0x{:x}) = 0x{:x}", address, result);
97        Ok(result)
98    }
99
100    pub fn lseek(&mut self, fd: u64, offset: isize, whence: u64) -> Result<u64> {
101        let whence = if whence == self.constants.SEEK_SET {
102            Whence::Set
103        } else if whence == self.constants.SEEK_CUR {
104            Whence::Cursor
105        } else if whence == self.constants.SEEK_END {
106            Whence::End
107        } else {
108            return Ok(-1i64 as u64);
109        };
110
111        self.file_system
112            .fd_seek(fd as usize, offset, whence)
113            .map(|off| off as u64)
114    }
115
116    #[allow(clippy::too_many_arguments)]
117    pub fn mmap(
118        &mut self,
119        memory: &mut Memory,
120        address: u64,
121        length: u64,
122        prot: u64,
123        flags: u64,
124        fd: u64,
125        offset: u64,
126    ) -> Result<u64> {
127        let mut permissions: MemoryPermissions = MemoryPermissions::NONE;
128
129        if flags & self.constants.MAP_ANONYMOUS == 0 && !self.file_system.fd_valid(fd as usize) {
130            return Ok(-1i64 as u64);
131        }
132
133        if prot & self.constants.PROT_READ > 0 {
134            permissions |= MemoryPermissions::READ;
135        }
136        if prot & self.constants.PROT_WRITE > 0 {
137            permissions |= MemoryPermissions::WRITE;
138        }
139        if prot & self.constants.PROT_EXEC > 0 {
140            permissions |= MemoryPermissions::EXECUTE;
141        }
142
143        let address = if address > 0 {
144            if address + length > self.mmap_address {
145                self.mmap_address = address + length;
146                if !self
147                    .mmap_address
148                    .is_multiple_of(crate::executor::PAGE_SIZE as u64)
149                {
150                    self.mmap_address += crate::executor::PAGE_SIZE as u64;
151                    self.mmap_address &= !(crate::executor::PAGE_SIZE as u64 - 1);
152                }
153            }
154            address
155        } else {
156            let address = self.mmap_address;
157            let permissions_length =
158                if !(length as usize).is_multiple_of(crate::executor::PAGE_SIZE) {
159                    let pl = length as usize + crate::executor::PAGE_SIZE;
160                    pl & (!(crate::executor::PAGE_SIZE - 1))
161                } else {
162                    length as usize
163                };
164            self.mmap_address += permissions_length as u64;
165            address
166        };
167
168        // this straight code-copying, ugly shiz. fix later
169        let permissions_length = if !(length as usize).is_multiple_of(crate::executor::PAGE_SIZE) {
170            let pl = length as usize + crate::executor::PAGE_SIZE;
171            pl & (!(crate::executor::PAGE_SIZE - 1))
172        } else {
173            length as usize
174        };
175
176        memory.set_permissions(address, permissions_length, Some(permissions))?;
177
178        if flags & self.constants.MAP_ANONYMOUS == 0 {
179            let mut filesize = self.file_system.size_fd(fd as usize).unwrap() as u64 - offset;
180            if filesize > length {
181                filesize = length;
182            }
183
184            let bytes = self.file_system.fd_bytes(fd as usize).unwrap();
185            for i in 0..filesize {
186                memory.store(address + i, &bytes[(offset + i) as usize])?;
187            }
188        }
189
190        Ok(address)
191    }
192
193    pub fn mprotect(
194        &mut self,
195        memory: &mut Memory,
196        address: u64,
197        length: u64,
198        prot: u64,
199    ) -> Result<u64> {
200        let mut permissions: MemoryPermissions = MemoryPermissions::NONE;
201
202        if prot & self.constants.PROT_READ > 0 {
203            permissions |= MemoryPermissions::READ;
204        }
205        if prot & self.constants.PROT_WRITE > 0 {
206            permissions |= MemoryPermissions::WRITE;
207        }
208        if prot & self.constants.PROT_EXEC > 0 {
209            permissions |= MemoryPermissions::EXECUTE;
210        }
211
212        let permissions_length = if !(length as usize).is_multiple_of(crate::executor::PAGE_SIZE) {
213            let pl = length as usize + crate::executor::PAGE_SIZE;
214            pl & (!(crate::executor::PAGE_SIZE - 1))
215        } else {
216            length as usize
217        };
218        memory.set_permissions(address, permissions_length, Some(permissions))?;
219
220        Ok(0)
221    }
222
223    pub fn open(&mut self, path: &str, flags: u64, _mode: u64) -> Result<u64> {
224        if flags & self.constants.O_CREAT > 0 {
225            self.file_system.create(path).map(|fd| fd as u64)
226        } else {
227            Ok(self
228                .file_system
229                .open(path)?
230                .map(|fd| fd as u64)
231                .unwrap_or(-1i64 as u64))
232        }
233    }
234
235    pub fn openat(&mut self, dirfd: u64, path: &str, flags: u64, mode: u64) -> Result<u64> {
236        if dirfd as u32 != AT_FDCWD {
237            bail!("openat not implemented for dirfd!=AT_FDCWD")
238        }
239        self.open(path, flags, mode)
240    }
241
242    pub fn read(&mut self, fd: u64, length: u64) -> Result<Option<Vec<il::Expression>>> {
243        self.file_system.read_fd(fd as usize, length as usize)
244    }
245
246    pub fn write(&mut self, fd: u64, data: Vec<il::Expression>) -> Result<u64> {
247        let len = data.len() as u64;
248        match self.file_system.write_fd(fd as usize, data) {
249            Ok(_) => Ok(len),
250            Err(_) => Ok(-1i64 as u64),
251        }
252    }
253}