finch/platform/linux/
linux_.rs1use 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#[derive(Clone, Debug, Eq, PartialEq, Serialize)]
19pub struct Linux {
20 brk_base: u64,
22 brk_address: u64,
24 constants: &'static Constants,
26 file_system: FileSystem,
28 mmap_address: u64,
30}
31
32impl Linux {
33 pub fn new(
35 elf_linker: &ElfLinker,
36 base_path: Option<PathBuf>,
37 constants: &'static Constants,
38 ) -> Result<Linux> {
39 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 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 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}