|
1 | 1 | use std::{ |
2 | | - time::Instant, |
3 | 2 | path::PathBuf, |
4 | | - process::{exit, Command}, |
5 | 3 | thread::{sleep, spawn}, |
| 4 | + process::{exit, Command}, |
| 5 | + time::{Instant, Duration}, |
6 | 6 | io::{Read, Seek, SeekFrom}, |
7 | 7 | os::unix::fs::{symlink, MetadataExt}, |
8 | | - {env::{self, current_exe}, fs, io, time}, |
| 8 | + {env::{self, current_exe}, fs, time}, |
| 9 | + io::{ErrorKind::NotFound, Error, Result}, |
9 | 10 | fs::{create_dir, create_dir_all, read_to_string, remove_dir, remove_file, File}, |
10 | 11 | }; |
11 | | -use io::{ErrorKind::NotFound, Error, Result}; |
12 | 12 |
|
13 | 13 | use which::which; |
14 | 14 | use cfg_if::cfg_if; |
15 | 15 | use goblin::elf::Elf; |
16 | 16 | use memfd_exec::{MemFdExecutable, Stdio}; |
17 | 17 | use nix::sys::{wait::waitpid, signal::{Signal, kill}}; |
18 | 18 | use nix::unistd::{access, fork, getcwd, AccessFlags, ForkResult, Pid}; |
19 | | -use signal_hook::{consts::{SIGINT, SIGTERM, SIGQUIT}, iterator::Signals}; |
| 19 | +use signal_hook::{consts::{SIGINT, SIGTERM, SIGQUIT, SIGHUP}, iterator::Signals}; |
20 | 20 |
|
21 | 21 | #[cfg(feature = "pie-ulexec")] |
22 | 22 | mod pie_ulexec { |
@@ -59,6 +59,7 @@ struct Image { |
59 | 59 | is_dwar: bool, |
60 | 60 | } |
61 | 61 |
|
| 62 | + |
62 | 63 | fn get_image(path: &PathBuf, offset: u64) -> Result<Image> { |
63 | 64 | let mut file = File::open(path)?; |
64 | 65 | let mut buffer = [0; 4]; |
@@ -167,38 +168,26 @@ fn is_pie(bytes: &Vec<u8>) -> bool { |
167 | 168 | } |
168 | 169 |
|
169 | 170 | fn get_runtime_size(path: &PathBuf) -> Result<u64> { |
170 | | - const MAX_SIZE: usize = 20971520; // 20 MB |
171 | | - const BUFFER_SIZE: usize = 1048576; // 1 MB |
172 | | - let mut runtime = File::open(path)?; |
173 | | - let mut buffer = Vec::with_capacity(MAX_SIZE); |
174 | | - let mut total_read = 0; |
175 | | - loop { |
176 | | - if total_read >= MAX_SIZE { |
177 | | - return Err(Error::new(std::io::ErrorKind::InvalidInput, |
178 | | - format!("Reached ELF runtime MAX_SIZE buffer limit of {} MB", MAX_SIZE / 1024 / 1024) |
179 | | - )); |
180 | | - } |
181 | | - let mut chunk = [0; BUFFER_SIZE]; |
182 | | - let bytes_read = runtime.read(&mut chunk)?; |
183 | | - if bytes_read == 0 { |
184 | | - return Err(Error::new(std::io::ErrorKind::UnexpectedEof, |
185 | | - format!("Reached end of file: {:?}", path) |
186 | | - )); |
187 | | - } |
188 | | - buffer.extend_from_slice(&chunk[..bytes_read]); |
189 | | - total_read += bytes_read; |
190 | | - if let Ok(elf) = Elf::parse(&buffer) { |
191 | | - let ehdr = elf.header; |
192 | | - let sht_end = ehdr.e_shoff + (ehdr.e_shentsize as u64 * ehdr.e_shnum as u64); |
193 | | - let last_shdr = elf.section_headers.last().unwrap(); |
194 | | - let last_section_end = last_shdr.sh_offset + last_shdr.sh_size; |
195 | | - return if sht_end > last_section_end { |
196 | | - Ok(sht_end) |
197 | | - } else { |
198 | | - Ok(last_section_end) |
199 | | - } |
200 | | - } else { continue } |
201 | | - } |
| 171 | + let mut file = File::open(path)?; |
| 172 | + let mut elf_header_raw = [0; 64]; |
| 173 | + file.read_exact(&mut elf_header_raw)?; |
| 174 | + let section_table_offset = u64::from_le_bytes(elf_header_raw[40..48].try_into().unwrap()); // e_shoff |
| 175 | + let section_count = u16::from_le_bytes(elf_header_raw[60..62].try_into().unwrap()); // e_shnum |
| 176 | + let section_table_size = section_count as u64 * 64; |
| 177 | + let required_bytes = section_table_offset + section_table_size; |
| 178 | + let mut header_data = vec![0; required_bytes as usize]; |
| 179 | + file.seek(SeekFrom::Start(0))?; |
| 180 | + file.read_exact(&mut header_data)?; |
| 181 | + let elf = Elf::parse(&header_data) |
| 182 | + .map_err(|e| std::io::Error::new(std::io::ErrorKind::InvalidData, e))?; |
| 183 | + let section_table_end = |
| 184 | + elf.header.e_shoff + (elf.header.e_shentsize as u64 * elf.header.e_shnum as u64); |
| 185 | + let last_section_end = elf |
| 186 | + .section_headers |
| 187 | + .last() |
| 188 | + .map(|section| section.sh_offset + section.sh_size) |
| 189 | + .unwrap_or(0); |
| 190 | + Ok(section_table_end.max(last_section_end)) |
202 | 191 | } |
203 | 192 |
|
204 | 193 | fn random_string(length: usize) -> String { |
@@ -269,7 +258,7 @@ fn embed_exec(exec_name: &str, exec_bytes: Vec<u8>, exec_args: Vec<String>) { |
269 | 258 | CString::new(format!("{}={}", key, value)).unwrap() |
270 | 259 | ).collect(); |
271 | 260 | spawn(move || { |
272 | | - sleep(time::Duration::from_millis(1)); |
| 261 | + sleep(Duration::from_millis(1)); |
273 | 262 | close(memfd_raw).unwrap() |
274 | 263 | }); |
275 | 264 | userland_execve::exec( |
@@ -302,14 +291,14 @@ fn is_mount_point(path: &PathBuf) -> Result<bool> { |
302 | 291 | } |
303 | 292 | } |
304 | 293 |
|
305 | | -fn wait_mount(path: &PathBuf, timeout: time::Duration) -> bool { |
| 294 | +fn wait_mount(path: &PathBuf, timeout: Duration) -> bool { |
306 | 295 | let start_time = Instant::now(); |
307 | 296 | while !path.exists() || !is_mount_point(path).unwrap_or(false) { |
308 | 297 | if start_time.elapsed() >= timeout { |
309 | 298 | eprintln!("Timeout reached while waiting for mount: {:?}", path); |
310 | 299 | return false |
311 | 300 | } |
312 | | - sleep(time::Duration::from_millis(1)) |
| 301 | + sleep(Duration::from_millis(1)) |
313 | 302 | } |
314 | 303 | true |
315 | 304 | } |
@@ -452,7 +441,7 @@ fn main() { |
452 | 441 |
|
453 | 442 | match unsafe { fork() } { |
454 | 443 | Ok(ForkResult::Parent { child: child_pid }) => { |
455 | | - if !wait_mount(&mount_dir, time::Duration::from_millis(500)) { |
| 444 | + if !wait_mount(&mount_dir, Duration::from_millis(1000)) { |
456 | 445 | remove_mnt(mount_dirs); |
457 | 446 | exit(1) |
458 | 447 | } |
@@ -494,7 +483,7 @@ fn main() { |
494 | 483 | spawn(move || { |
495 | 484 | for signal in signals.forever() { |
496 | 485 | match signal { |
497 | | - SIGINT | SIGTERM | SIGQUIT => { |
| 486 | + SIGINT | SIGTERM | SIGQUIT | SIGHUP => { |
498 | 487 | let _ = kill(pid, Signal::SIGTERM); |
499 | 488 | break |
500 | 489 | } |
|
0 commit comments