@@ -6,7 +6,7 @@ pub mod fs_tests {
66
77 use fdtables:: { translate_virtual_fd, FDTABLE } ;
88 use sysdefs:: constants:: err_const:: get_errno;
9- use sysdefs:: constants:: fs_const:: { SHMMAX , S_IRWXA } ;
9+ use sysdefs:: constants:: fs_const:: { SHMMAX , S_IRWXA , PAGESIZE } ;
1010 use sysdefs:: constants:: sys_const:: { DEFAULT_GID , DEFAULT_UID } ;
1111 use sysdefs:: data:: fs_struct:: { FSData , ShmidsStruct , StatData } ;
1212
@@ -772,6 +772,107 @@ pub mod fs_tests {
772772 lindrustfinalize ( ) ;
773773 }
774774
775+ #[ test]
776+ pub fn ut_lind_fs_mprotect_readwrite_test ( ) {
777+ // Acquire test lock and initialize environment
778+ let _thelock = setup:: lock_and_init ( ) ;
779+ let cage = interface:: cagetable_getref ( 1 ) ;
780+
781+
782+ // Create an anonymous memory mapping with read-only permissions
783+ // This simulates the C program's mmap() call to allocate a read-only page
784+ let readonlydata = cage. mmap_syscall (
785+ std:: ptr:: null_mut ( ) , // Let kernel choose address
786+ PAGESIZE as usize , // Map one page
787+ PROT_READ , // Initially read-only
788+ ( MAP_ANONYMOUS | MAP_PRIVATE ) as i32 , // Private anonymous mapping
789+ -1 , // No file descriptor for anonymous mapping
790+ 0 // Offset is ignored for anonymous mappings
791+ ) ;
792+ assert ! ( readonlydata >= 0 , "mmap should succeed" ) ;
793+
794+ // Change the protection to allow writing
795+ // This simulates the C program's mprotect() call to make the page writable
796+ let result = cage. mprotect_syscall (
797+ readonlydata as * mut u8 ,
798+ PAGESIZE as usize ,
799+ PROT_READ | PROT_WRITE // Add write permission
800+ ) ;
801+ assert_eq ! ( result, 0 , "mprotect should succeed" ) ;
802+
803+ // Test string to write to the now-writable memory
804+ let text = b"Mprotect write test text\0 " ;
805+ unsafe {
806+ // Copy test string into the mapped memory
807+ // This simulates the C program's memcpy() call
808+ let result = libc:: memcpy (
809+ readonlydata as * mut libc:: c_void ,
810+ text. as_ptr ( ) as * const libc:: c_void ,
811+ text. len ( )
812+ ) ;
813+
814+ // Verify that the write operation succeeded by comparing memory contents
815+ let written = std:: slice:: from_raw_parts ( readonlydata as * const u8 , text. len ( ) ) ;
816+ assert_eq ! ( written, text, "Written data should match test string" ) ;
817+
818+ // Print the written text to verify it's readable
819+ // This simulates the C program's puts() call
820+ }
821+
822+ // Clean up by unmapping the memory
823+ // This simulates the C program's munmap() call
824+ let result = cage. munmap_syscall ( readonlydata as * mut u8 , PAGESIZE as usize ) ;
825+ assert_eq ! ( result, 0 , "munmap should succeed" ) ;
826+
827+ // Clean up and exit
828+ assert_eq ! ( cage. exit_syscall( libc:: EXIT_SUCCESS ) , libc:: EXIT_SUCCESS ) ;
829+ lindrustfinalize ( ) ;
830+ }
831+
832+ #[ test]
833+ pub fn ut_lind_fs_mprotect_unmapped_addr ( ) {
834+ let _thelock = setup:: lock_and_init ( ) ;
835+ let cage = interface:: cagetable_getref ( 1 ) ;
836+
837+ // Try to protect an unmapped address
838+ let unmapped_addr = 0x1000 as * mut u8 ; // Some arbitrary address
839+ let result = cage. mprotect_syscall ( unmapped_addr, 4096 , PROT_READ ) ;
840+ assert_eq ! ( result, -( Errno :: ENOMEM as i32 ) , "mprotect should fail with ENOMEM for unmapped address" ) ;
841+
842+ assert_eq ! ( cage. exit_syscall( libc:: EXIT_SUCCESS ) , libc:: EXIT_SUCCESS ) ;
843+ lindrustfinalize ( ) ;
844+ }
845+
846+ #[ test]
847+ pub fn ut_lind_fs_mprotect_split_region ( ) {
848+ let _thelock = setup:: lock_and_init ( ) ;
849+ let cage = interface:: cagetable_getref ( 1 ) ;
850+
851+ // Map 4 pages with anonymous mapping
852+ let addr = cage. mmap_syscall (
853+ std:: ptr:: null_mut ( ) ,
854+ PAGESIZE as usize * 4 ,
855+ PROT_READ | PROT_WRITE ,
856+ ( MAP_PRIVATE | MAP_ANONYMOUS ) as i32 ,
857+ -1 ,
858+ 0
859+ ) ;
860+
861+ assert ! ( addr >= 0 , "mmap failed with error: {}" , addr) ;
862+
863+ // Change protection for middle two pages
864+ let middle_addr = ( addr as usize + PAGESIZE as usize ) as * mut u8 ;
865+ let result = cage. mprotect_syscall (
866+ middle_addr,
867+ PAGESIZE as usize * 2 ,
868+ PROT_READ
869+ ) ;
870+ assert_eq ! ( result, 0 , "mprotect failed" ) ;
871+
872+ // Clean up
873+ assert_eq ! ( cage. munmap_syscall( addr as * mut u8 , PAGESIZE as usize * 4 ) , 0 ) ;
874+ }
875+
775876 #[ test]
776877 pub fn ut_lind_fs_munmap_zerolen ( ) {
777878 //acquiring a lock on TESTMUTEX prevents other tests from running concurrently,
@@ -2895,7 +2996,7 @@ pub mod fs_tests {
28952996 assert_eq ! ( cage. fstat_syscall( fd1, & mut uselessstatdata) , 0 ) ;
28962997 assert_eq ! ( cage. fstat_syscall( fd2, & mut uselessstatdata) , 0 ) ;
28972998
2898- assert_eq ! ( cage. exec_syscall( 2 ) , 0 ) ;
2999+ assert_eq ! ( cage. exec_syscall( ) , 0 ) ;
28993000
29003001 let execcage = interface:: cagetable_getref ( 2 ) ;
29013002 assert_eq ! (
@@ -3101,7 +3202,6 @@ pub mod fs_tests {
31013202 // Now try to create a subdirectory under the parent directory
31023203 let c_subdir_path = std:: ffi:: CString :: new ( subdir_path) . unwrap ( ) ;
31033204 let result = unsafe { libc:: mkdir ( c_subdir_path. as_ptr ( ) , invalid_mode) } ;
3104- println ! ( "mkdir returned for subdir: {}" , result) ;
31053205
31063206 // Check if mkdir failed
31073207 if result != 0 {
0 commit comments