Add support for /proc/self(pid)/maps
This commit is contained in:
		
							parent
							
								
									dd295c1391
								
							
						
					
					
						commit
						d1acb84362
					
				| @ -266,6 +266,10 @@ impl File for INodeFile { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl INodeFile { | impl INodeFile { | ||||||
|  |     pub fn inode(&self) -> &Arc<dyn INode> { | ||||||
|  |         &self.inode | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn open(inode: Arc<dyn INode>, abs_path: &str, flags: u32) -> Result<Self> { |     pub fn open(inode: Arc<dyn INode>, abs_path: &str, flags: u32) -> Result<Self> { | ||||||
|         let access_mode = AccessMode::from_u32(flags)?; |         let access_mode = AccessMode::from_u32(flags)?; | ||||||
|         if (access_mode.readable() && !inode.allow_read()?) { |         if (access_mode.readable() && !inode.allow_read()?) { | ||||||
|  | |||||||
							
								
								
									
										134
									
								
								src/libos/src/fs/procfs/pid/maps.rs
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										134
									
								
								src/libos/src/fs/procfs/pid/maps.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,134 @@ | |||||||
|  | use super::*; | ||||||
|  | 
 | ||||||
|  | use crate::vm::{ChunkType, VMArea, VMPerms, VMRange}; | ||||||
|  | 
 | ||||||
|  | // This file is to implement /proc/self(pid)/maps file system.
 | ||||||
|  | //
 | ||||||
|  | // Print format:
 | ||||||
|  | // vmrange_start-vmrange_end, permission, shared/private, offset, device ID, inode, pathname
 | ||||||
|  | //
 | ||||||
|  | // Example:
 | ||||||
|  | // - cat /proc/self/maps
 | ||||||
|  | // 555555554000-555555556000 r--p 00000000 08:12 39321752                   /usr/bin/cat
 | ||||||
|  | // 555555556000-55555555b000 r-xp 00002000 08:12 39321752                   /usr/bin/cat
 | ||||||
|  | // 55555555b000-55555555e000 r--p 00007000 08:12 39321752                   /usr/bin/cat
 | ||||||
|  | // 55555555e000-55555555f000 r--p 00009000 08:12 39321752                   /usr/bin/cat
 | ||||||
|  | // 55555555f000-555555560000 rw-p 0000a000 08:12 39321752                   /usr/bin/cat
 | ||||||
|  | // 555555560000-555555581000 rw-p 00000000 00:00 0                          [heap]
 | ||||||
|  | // 7ffff7536000-7ffff7558000 rw-p 00000000 00:00 0
 | ||||||
|  | // 7ffff7558000-7ffff7dc8000 r--p 00000000 08:12 39322175                   /usr/lib/locale/locale-archive
 | ||||||
|  | // 7ffff7dc8000-7ffff7dea000 r--p 00000000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||||
|  | // 7ffff7dea000-7ffff7f62000 r-xp 00022000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||||
|  | // 7ffff7f62000-7ffff7fb0000 r--p 0019a000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||||
|  | // 7ffff7fb0000-7ffff7fb4000 r--p 001e7000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||||
|  | // 7ffff7fb4000-7ffff7fb6000 rw-p 001eb000 08:12 39324754                   /usr/lib/x86_64-linux-gnu/libc-2.31.so
 | ||||||
|  | // 7ffff7fb6000-7ffff7fbc000 rw-p 00000000 00:00 0
 | ||||||
|  | // 7ffff7fcf000-7ffff7fd0000 r--p 00000000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||||
|  | // 7ffff7fd0000-7ffff7ff3000 r-xp 00001000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||||
|  | // 7ffff7ff3000-7ffff7ffb000 r--p 00024000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||||
|  | // 7ffff7ffc000-7ffff7ffd000 r--p 0002c000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||||
|  | // 7ffff7ffd000-7ffff7ffe000 rw-p 0002d000 08:12 39324750                   /usr/lib/x86_64-linux-gnu/ld-2.31.so
 | ||||||
|  | // 7ffff7ffe000-7ffff7fff000 rw-p 00000000 00:00 0
 | ||||||
|  | // 7ffffffde000-7ffffffff000 rw-p 00000000 00:00 0                          [stack]
 | ||||||
|  | // 80000006b000-80000006f000 r--p 00000000 00:00 0                          [vvar]
 | ||||||
|  | // 80000006f000-800000071000 r-xp 00000000 00:00 0                          [vdso]
 | ||||||
|  | // ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0                  [vsyscall]
 | ||||||
|  | //
 | ||||||
|  | // Known limitation:
 | ||||||
|  | // - Device ID is not provided by FS
 | ||||||
|  | // - Not shown in address order
 | ||||||
|  | 
 | ||||||
|  | pub struct ProcMapsINode(ProcessRef); | ||||||
|  | 
 | ||||||
|  | impl ProcMapsINode { | ||||||
|  |     pub fn new(process_ref: &ProcessRef) -> Arc<dyn INode> { | ||||||
|  |         Arc::new(File::new(Self(Arc::clone(process_ref)))) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl ProcINode for ProcMapsINode { | ||||||
|  |     fn generate_data_in_bytes(&self) -> vfs::Result<Vec<u8>> { | ||||||
|  |         let result_string = { | ||||||
|  |             let main_thread = self.0.main_thread().unwrap(); | ||||||
|  |             let process_vm = main_thread.vm(); | ||||||
|  |             let heap_range = process_vm.heap_range(); | ||||||
|  |             let stack_range = process_vm.stack_range(); | ||||||
|  | 
 | ||||||
|  |             let process_vm_chunks = process_vm.mem_chunks().read().unwrap(); | ||||||
|  |             process_vm_chunks | ||||||
|  |                 .iter() | ||||||
|  |                 .map(|chunk| match chunk.internal() { | ||||||
|  |                     ChunkType::SingleVMA(vma) => { | ||||||
|  |                         let range = chunk.range(); | ||||||
|  |                         let heap_or_stack = if range == heap_range { | ||||||
|  |                             Some(" [heap]") | ||||||
|  |                         } else if range == stack_range { | ||||||
|  |                             Some(" [stack]") | ||||||
|  |                         } else { | ||||||
|  |                             None | ||||||
|  |                         }; | ||||||
|  |                         let vma = vma.lock().unwrap(); | ||||||
|  |                         get_output_for_vma(&vma, heap_or_stack) | ||||||
|  |                     } | ||||||
|  |                     ChunkType::MultiVMA(internal_manager) => { | ||||||
|  |                         let internal = internal_manager.lock().unwrap(); | ||||||
|  |                         let vmas_list = internal.chunk_manager().vmas(); | ||||||
|  |                         vmas_list | ||||||
|  |                             .iter() | ||||||
|  |                             .map(|obj| get_output_for_vma(obj.vma(), None)) | ||||||
|  |                             .fold(String::new(), |acc, vma_info| acc + &vma_info) | ||||||
|  |                     } | ||||||
|  |                 }) | ||||||
|  |                 .fold(String::new(), |acc, vma_info| acc + &vma_info) | ||||||
|  |         }; | ||||||
|  | 
 | ||||||
|  |         Ok(result_string.into_bytes()) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn get_output_for_vma(vma: &VMArea, heap_or_stack: Option<&str>) -> String { | ||||||
|  |     let range = vma.range(); | ||||||
|  |     let perms = vma.perms(); | ||||||
|  | 
 | ||||||
|  |     let (file_path, offset, device_id, inode_num) = { | ||||||
|  |         if let Some((file, offset)) = vma.init_file() { | ||||||
|  |             let inode_file = file.as_inode_file().unwrap(); | ||||||
|  |             let file_path = inode_file.abs_path(); | ||||||
|  |             let inode_num = inode_file.inode().metadata().unwrap().inode; | ||||||
|  |             let device_id = inode_file.inode().metadata().unwrap().dev; | ||||||
|  |             (file_path, offset, device_id, inode_num) | ||||||
|  |         } else if heap_or_stack.is_some() { | ||||||
|  |             (heap_or_stack.unwrap(), 0, 0, 0) | ||||||
|  |         } else { | ||||||
|  |             ("", 0, 0, 0) | ||||||
|  |         } | ||||||
|  |     }; | ||||||
|  | 
 | ||||||
|  |     let shared = vma.writeback_file().is_some(); | ||||||
|  |     print_each_map( | ||||||
|  |         range, perms, shared, offset, device_id, inode_num, file_path, | ||||||
|  |     ) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn print_each_map( | ||||||
|  |     range: &VMRange, | ||||||
|  |     perms: VMPerms, | ||||||
|  |     shared: bool, | ||||||
|  |     offset: usize, | ||||||
|  |     device_id: usize, | ||||||
|  |     inode_num: usize, | ||||||
|  |     file_path: &str, | ||||||
|  | ) -> String { | ||||||
|  |     let result_str = format!( | ||||||
|  |         "{:x}-{:x} {}{} {:08x} {} {}      {}\n", | ||||||
|  |         range.start(), | ||||||
|  |         range.end(), | ||||||
|  |         perms.display(), | ||||||
|  |         if shared { "s" } else { "p" }, | ||||||
|  |         offset, | ||||||
|  |         device_id, | ||||||
|  |         inode_num, | ||||||
|  |         file_path | ||||||
|  |     ); | ||||||
|  |     result_str | ||||||
|  | } | ||||||
| @ -7,6 +7,7 @@ use self::comm::ProcCommINode; | |||||||
| use self::cwd::ProcCwdSymINode; | use self::cwd::ProcCwdSymINode; | ||||||
| use self::exe::ProcExeSymINode; | use self::exe::ProcExeSymINode; | ||||||
| use self::fd::LockedProcFdDirINode; | use self::fd::LockedProcFdDirINode; | ||||||
|  | use self::maps::ProcMapsINode; | ||||||
| use self::root::ProcRootSymINode; | use self::root::ProcRootSymINode; | ||||||
| use self::stat::ProcStatINode; | use self::stat::ProcStatINode; | ||||||
| 
 | 
 | ||||||
| @ -15,6 +16,7 @@ mod comm; | |||||||
| mod cwd; | mod cwd; | ||||||
| mod exe; | mod exe; | ||||||
| mod fd; | mod fd; | ||||||
|  | mod maps; | ||||||
| mod root; | mod root; | ||||||
| mod stat; | mod stat; | ||||||
| 
 | 
 | ||||||
| @ -60,6 +62,9 @@ impl LockedPidDirINode { | |||||||
|         // stat
 |         // stat
 | ||||||
|         let stat_inode = ProcStatINode::new(&file.process_ref); |         let stat_inode = ProcStatINode::new(&file.process_ref); | ||||||
|         file.entries.insert(String::from("stat"), stat_inode); |         file.entries.insert(String::from("stat"), stat_inode); | ||||||
|  |         // maps
 | ||||||
|  |         let maps_inode = ProcMapsINode::new(&file.process_ref); | ||||||
|  |         file.entries.insert(String::from("maps"), maps_inode); | ||||||
| 
 | 
 | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -1,6 +1,6 @@ | |||||||
| use super::super::elf_file::*; | use super::super::elf_file::*; | ||||||
| use super::ThreadRef; | use super::ThreadRef; | ||||||
| use crate::fs::{FileMode, INodeExt}; | use crate::fs::{AsINodeFile, FileMode, INodeExt}; | ||||||
| use crate::prelude::*; | use crate::prelude::*; | ||||||
| use rcore_fs::vfs::{FileType, INode, Metadata}; | use rcore_fs::vfs::{FileType, INode, Metadata}; | ||||||
| use std::ffi::CString; | use std::ffi::CString; | ||||||
| @ -13,10 +13,10 @@ use std::ffi::CString; | |||||||
| pub fn load_exec_file_hdr_to_vec( | pub fn load_exec_file_hdr_to_vec( | ||||||
|     file_path: &str, |     file_path: &str, | ||||||
|     current_ref: &ThreadRef, |     current_ref: &ThreadRef, | ||||||
| ) -> Result<(Option<String>, Arc<dyn INode>, Vec<u8>, ElfHeader)> { | ) -> Result<(Option<String>, FileRef, Vec<u8>, ElfHeader)> { | ||||||
|     let (inode, file_buf, elf_hdr) = load_file_hdr_to_vec(&file_path, current_ref)?; |     let (file_ref, file_buf, elf_hdr) = load_file_hdr_to_vec(&file_path, current_ref)?; | ||||||
|     if elf_hdr.is_some() { |     if elf_hdr.is_some() { | ||||||
|         Ok((None, inode, file_buf, elf_hdr.unwrap())) |         Ok((None, file_ref, file_buf, elf_hdr.unwrap())) | ||||||
|     } else { |     } else { | ||||||
|         // loaded file is not Elf format, try script file
 |         // loaded file is not Elf format, try script file
 | ||||||
|         if !is_script_file(&file_buf) { |         if !is_script_file(&file_buf) { | ||||||
| @ -30,14 +30,14 @@ pub fn load_exec_file_hdr_to_vec( | |||||||
|                 "libos doesn't support executing binaries from \"/host\" directory" |                 "libos doesn't support executing binaries from \"/host\" directory" | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|         let (interp_inode, interp_buf, interp_hdr) = |         let (interp_file, interp_buf, interp_hdr) = | ||||||
|             load_file_hdr_to_vec(&interpreter_path, current_ref)?; |             load_file_hdr_to_vec(&interpreter_path, current_ref)?; | ||||||
|         let interp_hdr = if interp_hdr.is_none() { |         let interp_hdr = if interp_hdr.is_none() { | ||||||
|             return_errno!(ENOEXEC, "scrip interpreter is not ELF format"); |             return_errno!(ENOEXEC, "scrip interpreter is not ELF format"); | ||||||
|         } else { |         } else { | ||||||
|             interp_hdr.unwrap() |             interp_hdr.unwrap() | ||||||
|         }; |         }; | ||||||
|         Ok((Some(interpreter_path), interp_inode, interp_buf, interp_hdr)) |         Ok((Some(interpreter_path), interp_file, interp_buf, interp_hdr)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -72,13 +72,13 @@ fn parse_script_interpreter(file_buf: &Vec<u8>) -> Result<String> { | |||||||
| pub fn load_file_hdr_to_vec( | pub fn load_file_hdr_to_vec( | ||||||
|     file_path: &str, |     file_path: &str, | ||||||
|     current_ref: &ThreadRef, |     current_ref: &ThreadRef, | ||||||
| ) -> Result<(Arc<dyn INode>, Vec<u8>, Option<ElfHeader>)> { | ) -> Result<(FileRef, Vec<u8>, Option<ElfHeader>)> { | ||||||
|     let inode = current_ref |     let file_ref = current_ref | ||||||
|         .fs() |         .fs() | ||||||
|         .read() |         .read() | ||||||
|         .unwrap() |         .unwrap() | ||||||
|         .lookup_inode(file_path) |         .open_file(file_path, 0, FileMode::S_IRUSR)?; | ||||||
|         .map_err(|e| errno!(e.errno(), "cannot find the file"))?; |     let inode = file_ref.as_inode_file()?.inode(); | ||||||
| 
 | 
 | ||||||
|     // Make sure the final file to exec is not a directory
 |     // Make sure the final file to exec is not a directory
 | ||||||
|     let metadata = inode.metadata()?; |     let metadata = inode.metadata()?; | ||||||
| @ -105,12 +105,12 @@ pub fn load_file_hdr_to_vec( | |||||||
|         .read_elf64_lazy_as_vec() |         .read_elf64_lazy_as_vec() | ||||||
|         .map_err(|e| errno!(e.errno(), "failed to read the file"))?; |         .map_err(|e| errno!(e.errno(), "failed to read the file"))?; | ||||||
| 
 | 
 | ||||||
|     let elf_header = ElfFile::parse_elf_hdr(&inode, &mut file_buf); |     let elf_header = ElfFile::parse_elf_hdr(&file_ref, &mut file_buf); | ||||||
|     if let Ok(elf_header) = elf_header { |     if let Ok(elf_header) = elf_header { | ||||||
|         Ok((inode, file_buf, Some(elf_header))) |         Ok((file_ref, file_buf, Some(elf_header))) | ||||||
|     } else { |     } else { | ||||||
|         // this file is not ELF format or there is something wrong when parsing
 |         // this file is not ELF format or there is something wrong when parsing
 | ||||||
|         warn!("parse elf header error = {}", elf_header.err().unwrap()); |         warn!("parse elf header error = {}", elf_header.err().unwrap()); | ||||||
|         Ok((inode, file_buf, None)) |         Ok((file_ref, file_buf, None)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -166,7 +166,7 @@ fn new_process_common( | |||||||
|     parent_process: Option<ProcessRef>, |     parent_process: Option<ProcessRef>, | ||||||
| ) -> Result<ProcessRef> { | ) -> Result<ProcessRef> { | ||||||
|     let mut argv = argv.clone().to_vec(); |     let mut argv = argv.clone().to_vec(); | ||||||
|     let (is_script, elf_inode, mut elf_buf, elf_header) = |     let (is_script, elf_file, mut elf_buf, elf_header) = | ||||||
|         load_exec_file_hdr_to_vec(file_path, current_ref)?; |         load_exec_file_hdr_to_vec(file_path, current_ref)?; | ||||||
| 
 | 
 | ||||||
|     // elf_path might be different from file_path because file_path could lead to a script text file.
 |     // elf_path might be different from file_path because file_path could lead to a script text file.
 | ||||||
| @ -182,13 +182,13 @@ fn new_process_common( | |||||||
|         file_path.to_string() |         file_path.to_string() | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     let exec_elf_hdr = ElfFile::new(&elf_inode, &mut elf_buf, elf_header) |     let exec_elf_hdr = ElfFile::new(&elf_file, &mut elf_buf, elf_header) | ||||||
|         .cause_err(|e| errno!(e.errno(), "invalid executable"))?; |         .cause_err(|e| errno!(e.errno(), "invalid executable"))?; | ||||||
|     let ldso_path = exec_elf_hdr |     let ldso_path = exec_elf_hdr | ||||||
|         .elf_interpreter() |         .elf_interpreter() | ||||||
|         .ok_or_else(|| errno!(EINVAL, "cannot find the interpreter segment"))?; |         .ok_or_else(|| errno!(EINVAL, "cannot find the interpreter segment"))?; | ||||||
|     trace!("ldso_path = {:?}", ldso_path); |     trace!("ldso_path = {:?}", ldso_path); | ||||||
|     let (ldso_inode, mut ldso_elf_hdr_buf, ldso_elf_header) = |     let (ldso_file, mut ldso_elf_hdr_buf, ldso_elf_header) = | ||||||
|         load_file_hdr_to_vec(ldso_path, current_ref) |         load_file_hdr_to_vec(ldso_path, current_ref) | ||||||
|             .cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?; |             .cause_err(|e| errno!(e.errno(), "cannot load ld.so"))?; | ||||||
|     let ldso_elf_header = if ldso_elf_header.is_none() { |     let ldso_elf_header = if ldso_elf_header.is_none() { | ||||||
| @ -196,7 +196,7 @@ fn new_process_common( | |||||||
|     } else { |     } else { | ||||||
|         ldso_elf_header.unwrap() |         ldso_elf_header.unwrap() | ||||||
|     }; |     }; | ||||||
|     let ldso_elf_hdr = ElfFile::new(&ldso_inode, &mut ldso_elf_hdr_buf, ldso_elf_header) |     let ldso_elf_hdr = ElfFile::new(&ldso_file, &mut ldso_elf_hdr_buf, ldso_elf_header) | ||||||
|         .cause_err(|e| errno!(e.errno(), "invalid ld.so"))?; |         .cause_err(|e| errno!(e.errno(), "invalid ld.so"))?; | ||||||
| 
 | 
 | ||||||
|     let new_process_ref = { |     let new_process_ref = { | ||||||
|  | |||||||
| @ -15,7 +15,7 @@ const ELF64_HDR_SIZE: usize = 64; | |||||||
| pub struct ElfFile<'a> { | pub struct ElfFile<'a> { | ||||||
|     elf_buf: &'a [u8], |     elf_buf: &'a [u8], | ||||||
|     elf_inner: Elf<'a>, |     elf_inner: Elf<'a>, | ||||||
|     file_inode: &'a Arc<dyn INode>, |     file_ref: &'a FileRef, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<'a> Debug for ElfFile<'a> { | impl<'a> Debug for ElfFile<'a> { | ||||||
| @ -30,7 +30,7 @@ impl<'a> Debug for ElfFile<'a> { | |||||||
| 
 | 
 | ||||||
| impl<'a> ElfFile<'a> { | impl<'a> ElfFile<'a> { | ||||||
|     pub fn new( |     pub fn new( | ||||||
|         file_inode: &'a Arc<dyn INode>, |         file_ref: &'a FileRef, | ||||||
|         mut elf_buf: &'a mut [u8], |         mut elf_buf: &'a mut [u8], | ||||||
|         header: ElfHeader, |         header: ElfHeader, | ||||||
|     ) -> Result<ElfFile<'a>> { |     ) -> Result<ElfFile<'a>> { | ||||||
| @ -64,7 +64,7 @@ impl<'a> ElfFile<'a> { | |||||||
|                     intepreter_offset, |                     intepreter_offset, | ||||||
|                     intepreter_count |                     intepreter_count | ||||||
|                 ); |                 ); | ||||||
|                 file_inode.read_at( |                 file_ref.read_at( | ||||||
|                     intepreter_offset, |                     intepreter_offset, | ||||||
|                     &mut elf_buf[intepreter_offset..intepreter_offset + intepreter_count], |                     &mut elf_buf[intepreter_offset..intepreter_offset + intepreter_count], | ||||||
|                 ); |                 ); | ||||||
| @ -87,7 +87,7 @@ impl<'a> ElfFile<'a> { | |||||||
|         Ok(ElfFile { |         Ok(ElfFile { | ||||||
|             elf_buf, |             elf_buf, | ||||||
|             elf_inner, |             elf_inner, | ||||||
|             file_inode, |             file_ref, | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -107,11 +107,11 @@ impl<'a> ElfFile<'a> { | |||||||
|         self.elf_buf |         self.elf_buf | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn file_inode(&self) -> &Arc<dyn INode> { |     pub fn file_ref(&self) -> &FileRef { | ||||||
|         self.file_inode |         self.file_ref | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn parse_elf_hdr(inode: &Arc<dyn INode>, elf_buf: &mut Vec<u8>) -> Result<ElfHeader> { |     pub fn parse_elf_hdr(elf_file: &FileRef, elf_buf: &mut Vec<u8>) -> Result<ElfHeader> { | ||||||
|         // TODO: Sanity check the number of program headers..
 |         // TODO: Sanity check the number of program headers..
 | ||||||
|         let mut phdr_start = 0; |         let mut phdr_start = 0; | ||||||
|         let mut phdr_end = 0; |         let mut phdr_end = 0; | ||||||
| @ -130,7 +130,7 @@ impl<'a> ElfFile<'a> { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let program_hdr_table_size = elf_hdr.e_phnum * elf_hdr.e_phentsize; |         let program_hdr_table_size = elf_hdr.e_phnum * elf_hdr.e_phentsize; | ||||||
|         inode.read_at( |         elf_file.read_at( | ||||||
|             elf_hdr.e_phoff as usize, |             elf_hdr.e_phoff as usize, | ||||||
|             &mut elf_buf[hdr_size..hdr_size + (program_hdr_table_size as usize)], |             &mut elf_buf[hdr_size..hdr_size + (program_hdr_table_size as usize)], | ||||||
|         )?; |         )?; | ||||||
|  | |||||||
| @ -93,11 +93,10 @@ impl Chunk { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn new_single_vma_chunk(vm_range: &VMRange, options: &VMMapOptions) -> Result<Self> { |     pub fn new_single_vma_chunk(vm_range: &VMRange, options: &VMMapOptions) -> Result<Self> { | ||||||
|         let writeback_file = options.writeback_file().clone(); |  | ||||||
|         let vm_area = VMArea::new( |         let vm_area = VMArea::new( | ||||||
|             vm_range.clone(), |             vm_range.clone(), | ||||||
|             *options.perms(), |             *options.perms(), | ||||||
|             writeback_file, |             options.initializer().backed_file(), | ||||||
|             DUMMY_CHUNK_PROCESS_ID, |             DUMMY_CHUNK_PROCESS_ID, | ||||||
|         ); |         ); | ||||||
|         // Initialize the memory of the new range
 |         // Initialize the memory of the new range
 | ||||||
| @ -178,7 +177,7 @@ impl Chunk { | |||||||
|         if internal_manager.chunk_manager().free_size() < options.size() { |         if internal_manager.chunk_manager().free_size() < options.size() { | ||||||
|             return_errno!(ENOMEM, "no enough size without trying. try other chunks"); |             return_errno!(ENOMEM, "no enough size without trying. try other chunks"); | ||||||
|         } |         } | ||||||
|         internal_manager.chunk_manager().mmap(options) |         internal_manager.chunk_manager_mut().mmap(options) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn is_single_vma(&self) -> bool { |     pub fn is_single_vma(&self) -> bool { | ||||||
| @ -279,7 +278,11 @@ impl ChunkInternal { | |||||||
|         self.process_set.insert(pid); |         self.process_set.insert(pid); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn chunk_manager(&mut self) -> &mut ChunkManager { |     pub fn chunk_manager(&self) -> &ChunkManager { | ||||||
|  |         &self.chunk_manager | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn chunk_manager_mut(&mut self) -> &mut ChunkManager { | ||||||
|         &mut self.chunk_manager |         &mut self.chunk_manager | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -75,9 +75,10 @@ mod vm_util; | |||||||
| 
 | 
 | ||||||
| use self::vm_layout::VMLayout; | use self::vm_layout::VMLayout; | ||||||
| 
 | 
 | ||||||
| pub use self::chunk::ChunkRef; | pub use self::chunk::{ChunkRef, ChunkType}; | ||||||
| pub use self::process_vm::{MMapFlags, MRemapFlags, MSyncFlags, ProcessVM, ProcessVMBuilder}; | pub use self::process_vm::{MMapFlags, MRemapFlags, MSyncFlags, ProcessVM, ProcessVMBuilder}; | ||||||
| pub use self::user_space_vm::USER_SPACE_VM_MANAGER; | pub use self::user_space_vm::USER_SPACE_VM_MANAGER; | ||||||
|  | pub use self::vm_area::VMArea; | ||||||
| pub use self::vm_perms::VMPerms; | pub use self::vm_perms::VMPerms; | ||||||
| pub use self::vm_range::VMRange; | pub use self::vm_range::VMRange; | ||||||
| pub use self::vm_util::{VMInitializer, VMMapOptionsBuilder}; | pub use self::vm_util::{VMInitializer, VMMapOptionsBuilder}; | ||||||
|  | |||||||
| @ -7,7 +7,9 @@ use super::process::elf_file::{ElfFile, ProgramHeaderExt}; | |||||||
| use super::user_space_vm::USER_SPACE_VM_MANAGER; | use super::user_space_vm::USER_SPACE_VM_MANAGER; | ||||||
| use super::vm_area::VMArea; | use super::vm_area::VMArea; | ||||||
| use super::vm_perms::VMPerms; | use super::vm_perms::VMPerms; | ||||||
| use super::vm_util::{VMInitializer, VMMapAddr, VMMapOptions, VMMapOptionsBuilder, VMRemapOptions}; | use super::vm_util::{ | ||||||
|  |     FileBacked, VMInitializer, VMMapAddr, VMMapOptions, VMMapOptionsBuilder, VMRemapOptions, | ||||||
|  | }; | ||||||
| use std::collections::HashSet; | use std::collections::HashSet; | ||||||
| use std::sync::atomic::{AtomicUsize, Ordering}; | use std::sync::atomic::{AtomicUsize, Ordering}; | ||||||
| 
 | 
 | ||||||
| @ -117,7 +119,9 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> { | |||||||
|                     .size(elf_layout.size()) |                     .size(elf_layout.size()) | ||||||
|                     .align(elf_layout.align()) |                     .align(elf_layout.align()) | ||||||
|                     .perms(VMPerms::ALL) // set it to read | write | exec for simplicity
 |                     .perms(VMPerms::ALL) // set it to read | write | exec for simplicity
 | ||||||
|                     .initializer(VMInitializer::DoNothing()) |                     .initializer(VMInitializer::ElfSpecific { | ||||||
|  |                         elf_file: elf_file.file_ref().clone(), | ||||||
|  |                     }) | ||||||
|                     .build() |                     .build() | ||||||
|                     .map_err(|e| { |                     .map_err(|e| { | ||||||
|                         &self.handle_error_when_init(&chunks); |                         &self.handle_error_when_init(&chunks); | ||||||
| @ -244,7 +248,7 @@ impl<'a, 'b> ProcessVMBuilder<'a, 'b> { | |||||||
|                 } |                 } | ||||||
| 
 | 
 | ||||||
|                 // Bytes of file_size length are loaded from the ELF file
 |                 // Bytes of file_size length are loaded from the ELF file
 | ||||||
|                 elf_file.file_inode().read_at( |                 elf_file.file_ref().read_at( | ||||||
|                     file_offset, |                     file_offset, | ||||||
|                     &mut elf_proc_buf[mem_start_offset..mem_start_offset + file_size], |                     &mut elf_proc_buf[mem_start_offset..mem_start_offset + file_size], | ||||||
|                 ); |                 ); | ||||||
| @ -318,6 +322,14 @@ impl ProcessVM { | |||||||
|         &self.mem_chunks |         &self.mem_chunks | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     pub fn stack_range(&self) -> &VMRange { | ||||||
|  |         &self.stack_range | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn heap_range(&self) -> &VMRange { | ||||||
|  |         &self.heap_range | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     pub fn add_mem_chunk(&self, chunk: ChunkRef) { |     pub fn add_mem_chunk(&self, chunk: ChunkRef) { | ||||||
|         let mut mem_chunks = self.mem_chunks.write().unwrap(); |         let mut mem_chunks = self.mem_chunks.write().unwrap(); | ||||||
|         mem_chunks.insert(chunk); |         mem_chunks.insert(chunk); | ||||||
| @ -488,28 +500,22 @@ impl ProcessVM { | |||||||
|                 VMInitializer::DoNothing() |                 VMInitializer::DoNothing() | ||||||
|             } else { |             } else { | ||||||
|                 let file_ref = current!().file(fd)?; |                 let file_ref = current!().file(fd)?; | ||||||
|                 VMInitializer::LoadFromFile { |                 // Only shared, file-backed memory mappings have write-back files
 | ||||||
|                     file: file_ref, |                 let need_write_back = if flags.contains(MMapFlags::MAP_SHARED) { | ||||||
|                     offset: offset, |                     true | ||||||
|  |                 } else { | ||||||
|  |                     false | ||||||
|  |                 }; | ||||||
|  |                 VMInitializer::FileBacked { | ||||||
|  |                     file: FileBacked::new(file_ref, offset, need_write_back), | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|         }; |         }; | ||||||
|         // Only shared, file-backed memory mappings have write-back files
 |  | ||||||
|         let writeback_file = if flags.contains(MMapFlags::MAP_SHARED) { |  | ||||||
|             if let VMInitializer::LoadFromFile { file, offset } = &initializer { |  | ||||||
|                 Some((file.clone(), *offset)) |  | ||||||
|             } else { |  | ||||||
|                 None |  | ||||||
|             } |  | ||||||
|         } else { |  | ||||||
|             None |  | ||||||
|         }; |  | ||||||
|         let mmap_options = VMMapOptionsBuilder::default() |         let mmap_options = VMMapOptionsBuilder::default() | ||||||
|             .size(size) |             .size(size) | ||||||
|             .addr(addr_option) |             .addr(addr_option) | ||||||
|             .perms(perms) |             .perms(perms) | ||||||
|             .initializer(initializer) |             .initializer(initializer) | ||||||
|             .writeback_file(writeback_file) |  | ||||||
|             .build()?; |             .build()?; | ||||||
|         let mmap_addr = USER_SPACE_VM_MANAGER.mmap(&mmap_options)?; |         let mmap_addr = USER_SPACE_VM_MANAGER.mmap(&mmap_options)?; | ||||||
|         Ok(mmap_addr) |         Ok(mmap_addr) | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ use std::ops::{Deref, DerefMut}; | |||||||
| 
 | 
 | ||||||
| use super::vm_perms::VMPerms; | use super::vm_perms::VMPerms; | ||||||
| use super::vm_range::VMRange; | use super::vm_range::VMRange; | ||||||
|  | use super::vm_util::FileBacked; | ||||||
| use super::*; | use super::*; | ||||||
| 
 | 
 | ||||||
| use intrusive_collections::rbtree::{Link, RBTree}; | use intrusive_collections::rbtree::{Link, RBTree}; | ||||||
| @ -11,7 +12,7 @@ use intrusive_collections::{intrusive_adapter, KeyAdapter}; | |||||||
| pub struct VMArea { | pub struct VMArea { | ||||||
|     range: VMRange, |     range: VMRange, | ||||||
|     perms: VMPerms, |     perms: VMPerms, | ||||||
|     writeback_file: Option<(FileRef, usize)>, |     file_backed: Option<FileBacked>, | ||||||
|     pid: pid_t, |     pid: pid_t, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -19,13 +20,13 @@ impl VMArea { | |||||||
|     pub fn new( |     pub fn new( | ||||||
|         range: VMRange, |         range: VMRange, | ||||||
|         perms: VMPerms, |         perms: VMPerms, | ||||||
|         writeback_file: Option<(FileRef, usize)>, |         file_backed: Option<FileBacked>, | ||||||
|         pid: pid_t, |         pid: pid_t, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         Self { |         Self { | ||||||
|             range, |             range, | ||||||
|             perms, |             perms, | ||||||
|             writeback_file, |             file_backed, | ||||||
|             pid, |             pid, | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -38,20 +39,25 @@ impl VMArea { | |||||||
|         new_perms: VMPerms, |         new_perms: VMPerms, | ||||||
|         pid: pid_t, |         pid: pid_t, | ||||||
|     ) -> Self { |     ) -> Self { | ||||||
|         let new_writeback_file = vma.writeback_file.as_ref().map(|(file, file_offset)| { |         let new_backed_file = vma.file_backed.as_ref().map(|file| { | ||||||
|             let new_file = file.clone(); |             let mut new_file = file.clone(); | ||||||
|  |             let file_offset = file.offset(); | ||||||
| 
 | 
 | ||||||
|             let new_file_offset = if vma.start() < new_range.start() { |             let new_file_offset = if vma.start() < new_range.start() { | ||||||
|                 let vma_offset = new_range.start() - vma.start(); |                 let vma_offset = new_range.start() - vma.start(); | ||||||
|                 *file_offset + vma_offset |                 file_offset + vma_offset | ||||||
|             } else { |             } else { | ||||||
|                 let vma_offset = vma.start() - new_range.start(); |                 let vma_offset = vma.start() - new_range.start(); | ||||||
|                 debug_assert!(*file_offset >= vma_offset); |                 debug_assert!(file_offset >= vma_offset); | ||||||
|                 *file_offset - vma_offset |                 file_offset - vma_offset | ||||||
|             }; |             }; | ||||||
|             (new_file, new_file_offset) | 
 | ||||||
|  |             new_file.set_offset(new_file_offset); | ||||||
|  | 
 | ||||||
|  |             new_file | ||||||
|         }); |         }); | ||||||
|         Self::new(new_range, new_perms, new_writeback_file, pid) | 
 | ||||||
|  |         Self::new(new_range, new_perms, new_backed_file, pid) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn perms(&self) -> VMPerms { |     pub fn perms(&self) -> VMPerms { | ||||||
| @ -66,8 +72,20 @@ impl VMArea { | |||||||
|         self.pid |         self.pid | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn writeback_file(&self) -> &Option<(FileRef, usize)> { |     pub fn init_file(&self) -> Option<(&FileRef, usize)> { | ||||||
|         &self.writeback_file |         if let Some(file) = &self.file_backed { | ||||||
|  |             Some(file.init_file()) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn writeback_file(&self) -> Option<(&FileRef, usize)> { | ||||||
|  |         if let Some(file) = &self.file_backed { | ||||||
|  |             file.writeback_file() | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn set_perms(&mut self, new_perms: VMPerms) { |     pub fn set_perms(&mut self, new_perms: VMPerms) { | ||||||
| @ -103,15 +121,19 @@ impl VMArea { | |||||||
|         let old_start = self.start(); |         let old_start = self.start(); | ||||||
|         self.range.set_start(new_start); |         self.range.set_start(new_start); | ||||||
| 
 | 
 | ||||||
|         // If the updates to the VMA needs to write back to a file, then the
 |         if let Some(file) = self.file_backed.as_mut() { | ||||||
|         // file offset must be adjusted according to the new start address.
 |             if !file.need_write_back() { | ||||||
|         if let Some((_, offset)) = self.writeback_file.as_mut() { |                 return; | ||||||
|  |             } | ||||||
|  |             // If the updates to the VMA needs to write back to a file, then the
 | ||||||
|  |             // file offset must be adjusted according to the new start address.
 | ||||||
|  |             let offset = file.offset(); | ||||||
|             if old_start < new_start { |             if old_start < new_start { | ||||||
|                 *offset += new_start - old_start; |                 file.set_offset(offset + (new_start - old_start)); | ||||||
|             } else { |             } else { | ||||||
|                 // The caller must guarantee that the new start makes sense
 |                 // The caller must guarantee that the new start makes sense
 | ||||||
|                 debug_assert!(*offset >= old_start - new_start); |                 debug_assert!(offset >= old_start - new_start); | ||||||
|                 *offset -= old_start - new_start; |                 file.set_offset(offset - (old_start - new_start)); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -223,22 +245,3 @@ impl VMAObj { | |||||||
|         &self.vma |         &self.vma | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 |  | ||||||
| impl VMArea { |  | ||||||
|     pub fn new_obj( |  | ||||||
|         range: VMRange, |  | ||||||
|         perms: VMPerms, |  | ||||||
|         writeback_file: Option<(FileRef, usize)>, |  | ||||||
|         pid: pid_t, |  | ||||||
|     ) -> Box<VMAObj> { |  | ||||||
|         Box::new(VMAObj { |  | ||||||
|             link: Link::new(), |  | ||||||
|             vma: VMArea { |  | ||||||
|                 range, |  | ||||||
|                 perms, |  | ||||||
|                 writeback_file, |  | ||||||
|                 pid, |  | ||||||
|             }, |  | ||||||
|         }) |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -116,9 +116,13 @@ impl ChunkManager { | |||||||
|             .free_manager |             .free_manager | ||||||
|             .find_free_range_internal(size, align, addr)?; |             .find_free_range_internal(size, align, addr)?; | ||||||
|         let new_addr = new_range.start(); |         let new_addr = new_range.start(); | ||||||
|         let writeback_file = options.writeback_file().clone(); |  | ||||||
|         let current_pid = current!().process().pid(); |         let current_pid = current!().process().pid(); | ||||||
|         let new_vma = VMArea::new(new_range, *options.perms(), writeback_file, current_pid); |         let new_vma = VMArea::new( | ||||||
|  |             new_range, | ||||||
|  |             *options.perms(), | ||||||
|  |             options.initializer().backed_file(), | ||||||
|  |             current_pid, | ||||||
|  |         ); | ||||||
| 
 | 
 | ||||||
|         // Initialize the memory of the new range
 |         // Initialize the memory of the new range
 | ||||||
|         let buf = unsafe { new_vma.as_slice_mut() }; |         let buf = unsafe { new_vma.as_slice_mut() }; | ||||||
| @ -416,7 +420,7 @@ impl ChunkManager { | |||||||
| 
 | 
 | ||||||
|     /// Same as flush_vma, except that an extra condition on the file needs to satisfy.
 |     /// Same as flush_vma, except that an extra condition on the file needs to satisfy.
 | ||||||
|     pub fn flush_file_vma_with_cond<F: Fn(&FileRef) -> bool>(vma: &VMArea, cond_fn: F) { |     pub fn flush_file_vma_with_cond<F: Fn(&FileRef) -> bool>(vma: &VMArea, cond_fn: F) { | ||||||
|         let (file, file_offset) = match vma.writeback_file().as_ref() { |         let (file, file_offset) = match vma.writeback_file() { | ||||||
|             None => return, |             None => return, | ||||||
|             Some((file_and_offset)) => file_and_offset, |             Some((file_and_offset)) => file_and_offset, | ||||||
|         }; |         }; | ||||||
| @ -430,7 +434,7 @@ impl ChunkManager { | |||||||
|         if !cond_fn(file) { |         if !cond_fn(file) { | ||||||
|             return; |             return; | ||||||
|         } |         } | ||||||
|         file.write_at(*file_offset, unsafe { vma.as_slice() }); |         file.write_at(file_offset, unsafe { vma.as_slice() }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn find_mmap_region(&self, addr: usize) -> Result<VMRange> { |     pub fn find_mmap_region(&self, addr: usize) -> Result<VMRange> { | ||||||
|  | |||||||
| @ -184,7 +184,11 @@ impl VMManager { | |||||||
|                         "mmap with addr in existing default chunk: {:?}", |                         "mmap with addr in existing default chunk: {:?}", | ||||||
|                         chunk.range() |                         chunk.range() | ||||||
|                     ); |                     ); | ||||||
|                     return chunk_internal.lock().unwrap().chunk_manager().mmap(options); |                     return chunk_internal | ||||||
|  |                         .lock() | ||||||
|  |                         .unwrap() | ||||||
|  |                         .chunk_manager_mut() | ||||||
|  |                         .mmap(options); | ||||||
|                 } |                 } | ||||||
|                 ChunkType::SingleVMA(_) => { |                 ChunkType::SingleVMA(_) => { | ||||||
|                     match addr { |                     match addr { | ||||||
| @ -287,7 +291,7 @@ impl VMManager { | |||||||
|                         ChunkType::MultiVMA(manager) => manager |                         ChunkType::MultiVMA(manager) => manager | ||||||
|                             .lock() |                             .lock() | ||||||
|                             .unwrap() |                             .unwrap() | ||||||
|                             .chunk_manager() |                             .chunk_manager_mut() | ||||||
|                             .munmap_range(munmap_range)?, |                             .munmap_range(munmap_range)?, | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| @ -307,7 +311,7 @@ impl VMManager { | |||||||
|                 return manager |                 return manager | ||||||
|                     .lock() |                     .lock() | ||||||
|                     .unwrap() |                     .unwrap() | ||||||
|                     .chunk_manager() |                     .chunk_manager_mut() | ||||||
|                     .munmap_range(munmap_range); |                     .munmap_range(munmap_range); | ||||||
|             } |             } | ||||||
|             ChunkType::SingleVMA(_) => { |             ChunkType::SingleVMA(_) => { | ||||||
| @ -353,7 +357,7 @@ impl VMManager { | |||||||
|                 return manager |                 return manager | ||||||
|                     .lock() |                     .lock() | ||||||
|                     .unwrap() |                     .unwrap() | ||||||
|                     .chunk_manager() |                     .chunk_manager_mut() | ||||||
|                     .mprotect(addr, size, perms); |                     .mprotect(addr, size, perms); | ||||||
|             } |             } | ||||||
|             ChunkType::SingleVMA(_) => { |             ChunkType::SingleVMA(_) => { | ||||||
| @ -383,7 +387,7 @@ impl VMManager { | |||||||
|                 return manager |                 return manager | ||||||
|                     .lock() |                     .lock() | ||||||
|                     .unwrap() |                     .unwrap() | ||||||
|                     .chunk_manager() |                     .chunk_manager_mut() | ||||||
|                     .msync_by_range(&sync_range); |                     .msync_by_range(&sync_range); | ||||||
|             } |             } | ||||||
|             ChunkType::SingleVMA(vma) => { |             ChunkType::SingleVMA(vma) => { | ||||||
| @ -405,7 +409,7 @@ impl VMManager { | |||||||
|                     manager |                     manager | ||||||
|                         .lock() |                         .lock() | ||||||
|                         .unwrap() |                         .unwrap() | ||||||
|                         .chunk_manager() |                         .chunk_manager_mut() | ||||||
|                         .msync_by_file(sync_file); |                         .msync_by_file(sync_file); | ||||||
|                 } |                 } | ||||||
|                 ChunkType::SingleVMA(vma) => { |                 ChunkType::SingleVMA(vma) => { | ||||||
| @ -452,7 +456,7 @@ impl VMManager { | |||||||
|             ChunkType::MultiVMA(manager) => manager |             ChunkType::MultiVMA(manager) => manager | ||||||
|                 .lock() |                 .lock() | ||||||
|                 .unwrap() |                 .unwrap() | ||||||
|                 .chunk_manager() |                 .chunk_manager_mut() | ||||||
|                 .parse_mremap_options(options), |                 .parse_mremap_options(options), | ||||||
|             ChunkType::SingleVMA(vma) => { |             ChunkType::SingleVMA(vma) => { | ||||||
|                 self.parse_mremap_options_for_single_vma_chunk(options, vma) |                 self.parse_mremap_options_for_single_vma_chunk(options, vma) | ||||||
|  | |||||||
| @ -55,6 +55,26 @@ impl VMPerms { | |||||||
|             assert!(sgx_status == sgx_status_t::SGX_SUCCESS && retval == 0); |             assert!(sgx_status == sgx_status_t::SGX_SUCCESS && retval == 0); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn display(&self) -> String { | ||||||
|  |         let mut str = String::new(); | ||||||
|  |         if self.can_read() { | ||||||
|  |             str += "r"; | ||||||
|  |         } else { | ||||||
|  |             str += "-"; | ||||||
|  |         } | ||||||
|  |         if self.can_write() { | ||||||
|  |             str += "w"; | ||||||
|  |         } else { | ||||||
|  |             str += "-"; | ||||||
|  |         } | ||||||
|  |         if self.can_execute() { | ||||||
|  |             str += "x"; | ||||||
|  |         } else { | ||||||
|  |             str += "-"; | ||||||
|  |         } | ||||||
|  |         str | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for VMPerms { | impl Default for VMPerms { | ||||||
|  | |||||||
| @ -1,9 +1,8 @@ | |||||||
| use super::*; | use super::*; | ||||||
| 
 | 
 | ||||||
| // use super::vm_area::VMArea;
 |  | ||||||
| // use super::free_space_manager::VMFreeSpaceManager;
 |  | ||||||
| use super::vm_area::*; | use super::vm_area::*; | ||||||
| use super::vm_perms::VMPerms; | use super::vm_perms::VMPerms; | ||||||
|  | use crate::fs::FileMode; | ||||||
| use std::collections::BTreeSet; | use std::collections::BTreeSet; | ||||||
| 
 | 
 | ||||||
| use intrusive_collections::rbtree::{Link, RBTree}; | use intrusive_collections::rbtree::{Link, RBTree}; | ||||||
| @ -18,15 +17,19 @@ pub enum VMInitializer { | |||||||
|     CopyFrom { |     CopyFrom { | ||||||
|         range: VMRange, |         range: VMRange, | ||||||
|     }, |     }, | ||||||
|     LoadFromFile { |     FileBacked { | ||||||
|         file: FileRef, |         file: FileBacked, | ||||||
|         offset: usize, |     }, | ||||||
|  |     // For ELF files, there is specical handling to not copy all the contents of the file. This is only used for tracking.
 | ||||||
|  |     ElfSpecific { | ||||||
|  |         elf_file: FileRef, | ||||||
|     }, |     }, | ||||||
|     // For file-backed mremap which may move from old range to new range and read extra bytes from file
 |     // For file-backed mremap which may move from old range to new range and read extra bytes from file
 | ||||||
|     CopyOldAndReadNew { |     CopyOldAndReadNew { | ||||||
|         old_range: VMRange, |         old_range: VMRange, | ||||||
|         file: FileRef, |         file: FileRef, | ||||||
|         offset: usize, // read file from this offset
 |         offset: usize, // read file from this offset
 | ||||||
|  |         new_writeback_file: FileBacked, | ||||||
|     }, |     }, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -39,7 +42,7 @@ impl Default for VMInitializer { | |||||||
| impl VMInitializer { | impl VMInitializer { | ||||||
|     pub fn init_slice(&self, buf: &mut [u8]) -> Result<()> { |     pub fn init_slice(&self, buf: &mut [u8]) -> Result<()> { | ||||||
|         match self { |         match self { | ||||||
|             VMInitializer::DoNothing() => { |             VMInitializer::DoNothing() | VMInitializer::ElfSpecific { .. } => { | ||||||
|                 // Do nothing
 |                 // Do nothing
 | ||||||
|             } |             } | ||||||
|             VMInitializer::FillZeros() => { |             VMInitializer::FillZeros() => { | ||||||
| @ -55,10 +58,11 @@ impl VMInitializer { | |||||||
|                     *b = 0; |                     *b = 0; | ||||||
|                 } |                 } | ||||||
|             } |             } | ||||||
|             VMInitializer::LoadFromFile { file, offset } => { |             VMInitializer::FileBacked { file } => { | ||||||
|                 // TODO: make sure that read_at does not move file cursor
 |                 // TODO: make sure that read_at does not move file cursor
 | ||||||
|                 let len = file |                 let len = file | ||||||
|                     .read_at(*offset, buf) |                     .file_ref() | ||||||
|  |                     .read_at(file.offset(), buf) | ||||||
|                     .cause_err(|_| errno!(EACCES, "failed to init memory from file"))?; |                     .cause_err(|_| errno!(EACCES, "failed to init memory from file"))?; | ||||||
|                 for b in &mut buf[len..] { |                 for b in &mut buf[len..] { | ||||||
|                     *b = 0; |                     *b = 0; | ||||||
| @ -68,6 +72,7 @@ impl VMInitializer { | |||||||
|                 old_range, |                 old_range, | ||||||
|                 file, |                 file, | ||||||
|                 offset, |                 offset, | ||||||
|  |                 new_writeback_file, | ||||||
|             } => { |             } => { | ||||||
|                 // TODO: Handle old_range with non-readable subrange
 |                 // TODO: Handle old_range with non-readable subrange
 | ||||||
|                 let src_slice = unsafe { old_range.as_slice() }; |                 let src_slice = unsafe { old_range.as_slice() }; | ||||||
| @ -85,6 +90,66 @@ impl VMInitializer { | |||||||
|         } |         } | ||||||
|         Ok(()) |         Ok(()) | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     pub fn backed_file(&self) -> Option<FileBacked> { | ||||||
|  |         match self { | ||||||
|  |             VMInitializer::ElfSpecific { elf_file } => { | ||||||
|  |                 let file_ref = elf_file.clone(); | ||||||
|  |                 Some(FileBacked::new(file_ref, 0, false)) | ||||||
|  |             } | ||||||
|  |             VMInitializer::FileBacked { file } => Some(file.clone()), | ||||||
|  |             VMInitializer::CopyOldAndReadNew { | ||||||
|  |                 new_writeback_file, .. | ||||||
|  |             } => Some(new_writeback_file.clone()), | ||||||
|  |             _ => None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // This struct is used to record file-backed memory type.
 | ||||||
|  | #[derive(Debug, Clone)] | ||||||
|  | pub struct FileBacked { | ||||||
|  |     file: FileRef, | ||||||
|  |     offset: usize, | ||||||
|  |     write_back: bool, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl FileBacked { | ||||||
|  |     pub fn new(file: FileRef, offset: usize, write_back: bool) -> Self { | ||||||
|  |         Self { | ||||||
|  |             file, | ||||||
|  |             offset, | ||||||
|  |             write_back, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn file_ref(&self) -> &FileRef { | ||||||
|  |         &self.file | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn offset(&self) -> usize { | ||||||
|  |         self.offset | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn set_offset(&mut self, offset: usize) { | ||||||
|  |         self.offset = offset; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn need_write_back(&self) -> bool { | ||||||
|  |         self.write_back | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn init_file(&self) -> (&FileRef, usize) { | ||||||
|  |         (&self.file, self.offset) | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     pub fn writeback_file(&self) -> Option<(&FileRef, usize)> { | ||||||
|  |         if self.write_back { | ||||||
|  |             Some((&self.file, self.offset)) | ||||||
|  |         } else { | ||||||
|  |             None | ||||||
|  |         } | ||||||
|  |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Copy, Debug, PartialEq)] | #[derive(Clone, Copy, Debug, PartialEq)] | ||||||
| @ -118,8 +183,6 @@ pub struct VMMapOptions { | |||||||
|     perms: VMPerms, |     perms: VMPerms, | ||||||
|     addr: VMMapAddr, |     addr: VMMapAddr, | ||||||
|     initializer: VMInitializer, |     initializer: VMInitializer, | ||||||
|     // The content of the VMA can be written back to a given file at a given offset
 |  | ||||||
|     writeback_file: Option<(FileRef, usize)>, |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // VMMapOptionsBuilder is generated automatically, except the build function
 | // VMMapOptionsBuilder is generated automatically, except the build function
 | ||||||
| @ -165,14 +228,12 @@ impl VMMapOptionsBuilder { | |||||||
|             Some(initializer) => initializer.clone(), |             Some(initializer) => initializer.clone(), | ||||||
|             None => VMInitializer::default(), |             None => VMInitializer::default(), | ||||||
|         }; |         }; | ||||||
|         let writeback_file = self.writeback_file.take().unwrap_or_default(); |  | ||||||
|         Ok(VMMapOptions { |         Ok(VMMapOptions { | ||||||
|             size, |             size, | ||||||
|             align, |             align, | ||||||
|             perms, |             perms, | ||||||
|             addr, |             addr, | ||||||
|             initializer, |             initializer, | ||||||
|             writeback_file, |  | ||||||
|         }) |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| @ -197,10 +258,6 @@ impl VMMapOptions { | |||||||
|     pub fn initializer(&self) -> &VMInitializer { |     pub fn initializer(&self) -> &VMInitializer { | ||||||
|         &self.initializer |         &self.initializer | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     pub fn writeback_file(&self) -> &Option<(FileRef, usize)> { |  | ||||||
|         &self.writeback_file |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Clone, Copy, PartialEq)] | #[derive(Clone, Copy, PartialEq)] | ||||||
| @ -375,17 +432,18 @@ pub trait VMRemapParser { | |||||||
|             } |             } | ||||||
|             (MRemapFlags::None, VMRemapSizeType::Growing, Some((backed_file, offset))) => { |             (MRemapFlags::None, VMRemapSizeType::Growing, Some((backed_file, offset))) => { | ||||||
|                 // Update writeback file offset
 |                 // Update writeback file offset
 | ||||||
|                 let new_writeback_file = Some((backed_file.clone(), offset + vma.size())); |                 let vm_initializer_for_new_range = VMInitializer::FileBacked { | ||||||
|                 let vm_initializer_for_new_range = VMInitializer::LoadFromFile { |                     file: FileBacked::new( | ||||||
|                     file: backed_file.clone(), |                         backed_file.clone(), | ||||||
|                     offset: offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 |                         offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 | ||||||
|  |                         true, | ||||||
|  |                     ), | ||||||
|                 }; |                 }; | ||||||
|                 let mmap_opts = VMMapOptionsBuilder::default() |                 let mmap_opts = VMMapOptionsBuilder::default() | ||||||
|                     .size(new_size - old_size) |                     .size(new_size - old_size) | ||||||
|                     .addr(VMMapAddr::Need(old_range.end())) |                     .addr(VMMapAddr::Need(old_range.end())) | ||||||
|                     .perms(perms) |                     .perms(perms) | ||||||
|                     .initializer(vm_initializer_for_new_range) |                     .initializer(vm_initializer_for_new_range) | ||||||
|                     .writeback_file(new_writeback_file) |  | ||||||
|                     .build()?; |                     .build()?; | ||||||
|                 let ret_addr = Some(old_addr); |                 let ret_addr = Some(old_addr); | ||||||
|                 (Some(mmap_opts), ret_addr) |                 (Some(mmap_opts), ret_addr) | ||||||
| @ -421,18 +479,18 @@ pub trait VMRemapParser { | |||||||
|                     VMRange::new_with_size(old_addr + old_size, new_size - old_size)?; |                     VMRange::new_with_size(old_addr + old_size, new_size - old_size)?; | ||||||
|                 if self.is_free_range(&prefered_new_range) { |                 if self.is_free_range(&prefered_new_range) { | ||||||
|                     // Don't need to move the old range
 |                     // Don't need to move the old range
 | ||||||
|                     let vm_initializer_for_new_range = VMInitializer::LoadFromFile { |                     let vm_initializer_for_new_range = VMInitializer::FileBacked { | ||||||
|                         file: backed_file.clone(), |                         file: FileBacked::new( | ||||||
|                         offset: offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 |                             backed_file.clone(), | ||||||
|  |                             offset + vma.size(), // file-backed mremap should start from the end of previous mmap/mremap file
 | ||||||
|  |                             true, | ||||||
|  |                         ), | ||||||
|                     }; |                     }; | ||||||
|                     // Write back file should start from new offset
 |  | ||||||
|                     let new_writeback_file = Some((backed_file.clone(), offset + vma.size())); |  | ||||||
|                     let mmap_ops = VMMapOptionsBuilder::default() |                     let mmap_ops = VMMapOptionsBuilder::default() | ||||||
|                         .size(prefered_new_range.size()) |                         .size(prefered_new_range.size()) | ||||||
|                         .addr(VMMapAddr::Need(prefered_new_range.start())) |                         .addr(VMMapAddr::Need(prefered_new_range.start())) | ||||||
|                         .perms(perms) |                         .perms(perms) | ||||||
|                         .initializer(vm_initializer_for_new_range) |                         .initializer(vm_initializer_for_new_range) | ||||||
|                         .writeback_file(new_writeback_file) |  | ||||||
|                         .build()?; |                         .build()?; | ||||||
|                     (Some(mmap_ops), Some(old_addr)) |                     (Some(mmap_ops), Some(old_addr)) | ||||||
|                 } else { |                 } else { | ||||||
| @ -441,19 +499,19 @@ pub trait VMRemapParser { | |||||||
|                         let copy_end = vma.end(); |                         let copy_end = vma.end(); | ||||||
|                         let copy_range = VMRange::new(old_range.start(), copy_end)?; |                         let copy_range = VMRange::new(old_range.start(), copy_end)?; | ||||||
|                         let reread_file_start_offset = copy_end - vma.start(); |                         let reread_file_start_offset = copy_end - vma.start(); | ||||||
|  |                         let new_writeback_file = FileBacked::new(backed_file.clone(), offset, true); | ||||||
|                         VMInitializer::CopyOldAndReadNew { |                         VMInitializer::CopyOldAndReadNew { | ||||||
|                             old_range: copy_range, |                             old_range: copy_range, | ||||||
|                             file: backed_file.clone(), |                             file: backed_file.clone(), | ||||||
|                             offset: reread_file_start_offset, |                             offset: reread_file_start_offset, | ||||||
|  |                             new_writeback_file: new_writeback_file, | ||||||
|                         } |                         } | ||||||
|                     }; |                     }; | ||||||
|                     let new_writeback_file = Some((backed_file.clone(), *offset)); |  | ||||||
|                     let mmap_ops = VMMapOptionsBuilder::default() |                     let mmap_ops = VMMapOptionsBuilder::default() | ||||||
|                         .size(new_size) |                         .size(new_size) | ||||||
|                         .addr(VMMapAddr::Any) |                         .addr(VMMapAddr::Any) | ||||||
|                         .perms(perms) |                         .perms(perms) | ||||||
|                         .initializer(vm_initializer_for_new_range) |                         .initializer(vm_initializer_for_new_range) | ||||||
|                         .writeback_file(new_writeback_file) |  | ||||||
|                         .build()?; |                         .build()?; | ||||||
|                     // Cannot determine the returned address for now, which can only be obtained after calling mmap
 |                     // Cannot determine the returned address for now, which can only be obtained after calling mmap
 | ||||||
|                     let ret_addr = None; |                     let ret_addr = None; | ||||||
| @ -476,19 +534,19 @@ pub trait VMRemapParser { | |||||||
|                     let copy_end = vma.end(); |                     let copy_end = vma.end(); | ||||||
|                     let copy_range = VMRange::new(old_range.start(), copy_end)?; |                     let copy_range = VMRange::new(old_range.start(), copy_end)?; | ||||||
|                     let reread_file_start_offset = copy_end - vma.start(); |                     let reread_file_start_offset = copy_end - vma.start(); | ||||||
|  |                     let new_writeback_file = FileBacked::new(backed_file.clone(), offset, true); | ||||||
|                     VMInitializer::CopyOldAndReadNew { |                     VMInitializer::CopyOldAndReadNew { | ||||||
|                         old_range: copy_range, |                         old_range: copy_range, | ||||||
|                         file: backed_file.clone(), |                         file: backed_file.clone(), | ||||||
|                         offset: reread_file_start_offset, |                         offset: reread_file_start_offset, | ||||||
|  |                         new_writeback_file: new_writeback_file, | ||||||
|                     } |                     } | ||||||
|                 }; |                 }; | ||||||
|                 let new_writeback_file = Some((backed_file.clone(), *offset)); |  | ||||||
|                 let mmap_opts = VMMapOptionsBuilder::default() |                 let mmap_opts = VMMapOptionsBuilder::default() | ||||||
|                     .size(new_size) |                     .size(new_size) | ||||||
|                     .addr(VMMapAddr::Force(new_addr)) |                     .addr(VMMapAddr::Force(new_addr)) | ||||||
|                     .perms(perms) |                     .perms(perms) | ||||||
|                     .initializer(vm_initializer_for_new_range) |                     .initializer(vm_initializer_for_new_range) | ||||||
|                     .writeback_file(new_writeback_file) |  | ||||||
|                     .build()?; |                     .build()?; | ||||||
|                 let ret_addr = Some(new_addr); |                 let ret_addr = Some(new_addr); | ||||||
|                 (Some(mmap_opts), ret_addr) |                 (Some(mmap_opts), ret_addr) | ||||||
|  | |||||||
| @ -44,6 +44,7 @@ static int test_read_from_procfs(const char *proc_inode) { | |||||||
|         } |         } | ||||||
|     } while (len == sizeof(buf)); |     } while (len == sizeof(buf)); | ||||||
|     close(fd); |     close(fd); | ||||||
|  |     printf("test read from %s:\n%s\n", proc_inode, buf); | ||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -89,6 +90,15 @@ static int test_readlink_from_proc_self_cwd() { | |||||||
|     return 0; |     return 0; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static int test_read_from_proc_self_maps() { | ||||||
|  |     const char *proc_maps = "/proc/self/maps"; | ||||||
|  | 
 | ||||||
|  |     if (test_read_from_procfs(proc_maps) < 0) { | ||||||
|  |         THROW_ERROR("failed to read the cpuinfo"); | ||||||
|  |     } | ||||||
|  |     return 0; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static int test_readlink_from_proc_self_root() { | static int test_readlink_from_proc_self_root() { | ||||||
|     char root_buf[PATH_MAX] = { 0 }; |     char root_buf[PATH_MAX] = { 0 }; | ||||||
|     const char *proc_root = "/proc/self/root"; |     const char *proc_root = "/proc/self/root"; | ||||||
| @ -282,6 +292,7 @@ static test_case_t test_cases[] = { | |||||||
|     TEST_CASE(test_readdir_root), |     TEST_CASE(test_readdir_root), | ||||||
|     TEST_CASE(test_readdir_self), |     TEST_CASE(test_readdir_self), | ||||||
|     TEST_CASE(test_readdir_self_fd), |     TEST_CASE(test_readdir_self_fd), | ||||||
|  |     TEST_CASE(test_read_from_proc_self_maps), | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| int main(int argc, const char *argv[]) { | int main(int argc, const char *argv[]) { | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user