1010#include <stdlib.h>
1111#include <string.h>
1212#include <sys/mman.h>
13- #include <sys/prctl.h>
1413#include <unistd.h>
1514
1615#include <elf.h>
@@ -414,57 +413,6 @@ static bool find_dynsym_value(int fd, const struct elf_dyn_info *info, const cha
414413 return false;
415414}
416415
417- /* INFO: Apply VMA names to anonymous mappings in a region via remote prctl. */
418- static bool apply_vma_names (int pid , struct user_regs_struct * regs , uintptr_t prctl_addr ,
419- uintptr_t libc_return_addr , uintptr_t region_start , size_t region_len ,
420- uintptr_t name_ptr ) {
421- char pid_maps [64 ];
422- snprintf (pid_maps , sizeof (pid_maps ), "/proc/%d/maps" , pid );
423-
424- struct maps * current_maps = parse_maps (pid_maps );
425- if (!current_maps ) {
426- LOGE ("Failed to parse remote process maps" );
427-
428- return false;
429- }
430-
431- uintptr_t region_end = region_start + region_len ;
432- struct user_regs_struct call_regs ;
433-
434- for (size_t i = 0 ; i < current_maps -> size ; i ++ ) {
435- struct map * m = & current_maps -> maps [i ];
436-
437- /* INFO: Skip VMAs outside our region */
438- if (m -> end <= region_start || m -> start >= region_end ) continue ;
439-
440- /* INFO: Skip non-anonymous mappings (backed by files) */
441- if (m -> dev != 0 || m -> inode != 0 ) continue ;
442-
443- size_t vma_len = m -> end - m -> start ;
444-
445- call_regs = * regs ;
446- long prctl_args [5 ];
447- prctl_args [0 ] = PR_SET_VMA ;
448- prctl_args [1 ] = PR_SET_VMA_ANON_NAME ;
449- prctl_args [2 ] = (long )m -> start ;
450- prctl_args [3 ] = (long )vma_len ;
451- prctl_args [4 ] = (long )name_ptr ;
452-
453- uintptr_t rc = remote_call (pid , & call_regs , prctl_addr , libc_return_addr , prctl_args , 5 );
454- if (rc != 0 ) {
455- LOGE ("Failed to set VMA name for region 0x%" PRIxPTR "-0x%" PRIxPTR ": prctl returned %p" , (uintptr_t )m -> start , (uintptr_t )m -> end , (void * )rc );
456-
457- free_maps (current_maps );
458-
459- return false;
460- }
461- }
462-
463- free_maps (current_maps );
464-
465- return true;
466- }
467-
468416#ifdef __LP64__
469417 #define ELF_R_TYPE ELF64_R_TYPE
470418 #define ELF_R_SYM ELF64_R_SYM
@@ -759,29 +707,91 @@ bool remote_csoloader_load_and_resolve_entry(int pid, struct user_regs_struct *r
759707 return false;
760708 }
761709
762- void * prctl_addr = find_func_addr (local_map , remote_map , libc_path , "prctl" );
763- if (!prctl_addr ) {
764- LOGE ("Failed to resolve remote prctl" );
710+ void * open_addr = find_func_addr (local_map , remote_map , libc_path , "open" );
711+ if (!open_addr ) {
712+ LOGE ("Failed to resolve remote open" );
713+
714+ free (phdr );
715+ close (fd );
716+
717+ return false;
718+ }
719+
720+ void * close_addr = find_func_addr (local_map , remote_map , libc_path , "close" );
721+ if (!close_addr ) {
722+ LOGE ("Failed to resolve remote close" );
765723
766724 free (phdr );
767725 close (fd );
768726
769727 return false;
770728 }
771729
772- /* INFO: Reserve address space with PROT_NONE */
773730 long args [6 ];
731+
732+ /* INFO: Copy library path into remote memory for file-backed mappings */
733+ size_t path_len = strlen (lib_path ) + 1 ;
734+ args [0 ] = 0 ;
735+ args [1 ] = (long )path_len ;
736+ args [2 ] = PROT_READ | PROT_WRITE ;
737+ args [3 ] = MAP_PRIVATE | MAP_ANONYMOUS ;
738+ args [4 ] = -1 ;
739+ args [5 ] = 0 ;
740+
741+ struct user_regs_struct call_regs = regs_saved ;
742+ uintptr_t remote_path = remote_call (pid , & call_regs , (uintptr_t )mmap_addr , libc_return_addr , args , 6 );
743+ if (!remote_path || remote_path == (uintptr_t )MAP_FAILED ) {
744+ LOGE ("remote mmap for path failed: %p" , (void * )remote_path );
745+
746+ free (phdr );
747+ close (fd );
748+
749+ return false;
750+ }
751+
752+ if (write_proc (pid , remote_path , lib_path , path_len ) != (ssize_t )path_len ) {
753+ LOGE ("Failed to write remote path string" );
754+
755+ free (phdr );
756+ close (fd );
757+
758+ return false;
759+ }
760+
761+ args [0 ] = (long )remote_path ;
762+ args [1 ] = O_RDONLY | O_CLOEXEC ;
763+ args [2 ] = 0 ;
764+
765+ call_regs = regs_saved ;
766+ long remote_fd = (long )remote_call (pid , & call_regs , (uintptr_t )open_addr , libc_return_addr , args , 3 );
767+ if (remote_fd < 0 ) {
768+ LOGE ("Failed to open remote file: %s" , lib_path );
769+
770+ free (phdr );
771+ close (fd );
772+
773+ return false;
774+ }
775+
776+ /* INFO: Reserve address space with PROT_NONE */
774777 args [0 ] = 0 ;
775778 args [1 ] = (long )map_size ;
776779 args [2 ] = PROT_NONE ;
777780 args [3 ] = MAP_PRIVATE | MAP_ANONYMOUS ;
778781 args [4 ] = -1 ;
779782 args [5 ] = 0 ;
780783
781- struct user_regs_struct call_regs = regs_saved ;
784+ call_regs = regs_saved ;
782785 uintptr_t remote_base = remote_call (pid , & call_regs , (uintptr_t )mmap_addr , libc_return_addr , args , 6 );
783786 if (!remote_base || remote_base == (uintptr_t )MAP_FAILED ) {
784787 LOGE ("remote mmap reserve failed: %p" , (void * )remote_base );
788+
789+ call_regs = regs_saved ;
790+
791+ args [0 ] = remote_fd ;
792+
793+ remote_call (pid , & call_regs , (uintptr_t )close_addr , libc_return_addr , args , 1 );
794+
785795 free (phdr );
786796 close (fd );
787797
@@ -799,7 +809,7 @@ bool remote_csoloader_load_and_resolve_entry(int pid, struct user_regs_struct *r
799809
800810 size_t segs_count = 0 ;
801811
802- /* INFO: Map each PT_LOAD as anonymous RW, copy file bytes, record final permissions */
812+ /* INFO: Map non-writable PT_LOAD from file */
803813 for (int i = 0 ; i < eh .e_phnum ; i ++ ) {
804814 if (phdr [i ].p_type != PT_LOAD ) continue ;
805815
@@ -809,39 +819,106 @@ bool remote_csoloader_load_and_resolve_entry(int pid, struct user_regs_struct *r
809819 uintptr_t seg_page_end = page_end (seg_end , page_size );
810820 size_t seg_page_len = (size_t )(seg_page_end - seg_page );
811821
812- args [0 ] = (long )seg_page ;
813- args [1 ] = (long )seg_page_len ;
814- args [2 ] = PROT_READ | PROT_WRITE ;
815- args [3 ] = MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS ;
816- args [4 ] = -1 ;
817- args [5 ] = 0 ;
822+ bool is_writable = (phdr [i ].p_flags & PF_W ) != 0 ;
818823
819- call_regs = regs_saved ;
820- uintptr_t seg_map = remote_call (pid , & call_regs , (uintptr_t )mmap_addr , libc_return_addr , args , 6 );
821- if (!seg_map || seg_map == (uintptr_t )MAP_FAILED ) {
822- LOGE ("remote mmap segment failed for phdr %d" , i );
823- free (phdr );
824- close (fd );
824+ if (is_writable ) {
825+ args [0 ] = (long )seg_page ;
826+ args [1 ] = (long )seg_page_len ;
827+ args [2 ] = PROT_READ | PROT_WRITE ;
828+ args [3 ] = MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS ;
829+ args [4 ] = -1 ;
830+ args [5 ] = 0 ;
825831
826- return false;
827- }
832+ call_regs = regs_saved ;
833+ uintptr_t seg_map = remote_call (pid , & call_regs , (uintptr_t )mmap_addr , libc_return_addr , args , 6 );
834+ if (!seg_map || seg_map == (uintptr_t )MAP_FAILED ) {
835+ LOGE ("remote mmap writable segment failed for phdr %d" , i );
828836
829- /* INFO: Copy segment file content to remote in one shot. BSS (p_memsz > p_filesz)
830- is already zeroed by kernel since we used MAP_ANONYMOUS. */
831- size_t filesz = (size_t )phdr [i ].p_filesz ;
832- if (filesz > 0 ) {
833- char * buf = (char * )malloc (filesz );
834- if (!buf || !read_loop_offset (fd , buf , filesz , (off_t )phdr [i ].p_offset ) || write_proc (pid , seg_start , buf , filesz ) != (ssize_t )filesz ) {
835- LOGE ("Failed to copy segment data for phdr %d" , i );
837+ call_regs = regs_saved ;
836838
837- free (buf );
839+ args [0 ] = remote_fd ;
840+
841+ remote_call (pid , & call_regs , (uintptr_t )close_addr , libc_return_addr , args , 1 );
838842 free (phdr );
839843 close (fd );
840844
841845 return false;
842846 }
843847
844- free (buf );
848+ size_t filesz = (size_t )phdr [i ].p_filesz ;
849+ if (filesz > 0 ) {
850+ char * buf = (char * )malloc (filesz );
851+ if (!buf || !read_loop_offset (fd , buf , filesz , (off_t )phdr [i ].p_offset ) || write_proc (pid , seg_start , buf , filesz ) != (ssize_t )filesz ) {
852+ LOGE ("Failed to copy segment data for phdr %d" , i );
853+
854+ free (buf );
855+ free (phdr );
856+ close (fd );
857+
858+ return false;
859+ }
860+
861+ free (buf );
862+ }
863+ } else {
864+ off_t seg_offset = (off_t )phdr [i ].p_offset ;
865+ off_t file_page_offset = (off_t )page_start ((uintptr_t )seg_offset , page_size );
866+ uintptr_t file_end = (uintptr_t )phdr [i ].p_vaddr + (uintptr_t )phdr [i ].p_filesz + load_bias ;
867+ uintptr_t file_page_end = page_end (file_end , page_size );
868+
869+ if (phdr [i ].p_filesz > 0 ) {
870+ call_regs = regs_saved ;
871+
872+ size_t file_map_len = (size_t )(file_page_end - seg_page );
873+ args [0 ] = (long )seg_page ;
874+ args [1 ] = (long )file_map_len ;
875+ args [2 ] = PROT_READ | PROT_WRITE ;
876+ args [3 ] = MAP_FIXED | MAP_PRIVATE ;
877+ args [4 ] = remote_fd ;
878+ args [5 ] = (long )file_page_offset ;
879+
880+ uintptr_t seg_map = remote_call (pid , & call_regs , (uintptr_t )mmap_addr , libc_return_addr , args , 6 );
881+ if (!seg_map || seg_map == (uintptr_t )MAP_FAILED ) {
882+ LOGE ("remote mmap file-backed segment failed for phdr %d" , i );
883+
884+ call_regs = regs_saved ;
885+
886+ args [0 ] = remote_fd ;
887+
888+ remote_call (pid , & call_regs , (uintptr_t )close_addr , libc_return_addr , args , 1 );
889+ free (phdr );
890+ close (fd );
891+
892+ return false;
893+ }
894+ }
895+
896+ if (seg_page_end > file_page_end ) {
897+ call_regs = regs_saved ;
898+
899+ args [0 ] = (long )file_page_end ;
900+ args [1 ] = (long )(seg_page_end - file_page_end );
901+ args [2 ] = PROT_READ | PROT_WRITE ;
902+ args [3 ] = MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS ;
903+ args [4 ] = -1 ;
904+ args [5 ] = 0 ;
905+
906+ uintptr_t bss_map = remote_call (pid , & call_regs , (uintptr_t )mmap_addr , libc_return_addr , args , 6 );
907+ if (!bss_map || bss_map == (uintptr_t )MAP_FAILED ) {
908+ LOGE ("remote mmap bss segment failed for phdr %d" , i );
909+
910+ call_regs = regs_saved ;
911+
912+ args [0 ] = remote_fd ;
913+
914+ call_regs = regs_saved ;
915+ remote_call (pid , & call_regs , (uintptr_t )close_addr , libc_return_addr , args , 1 );
916+ free (phdr );
917+ close (fd );
918+
919+ return false;
920+ }
921+ }
845922 }
846923
847924 /* INFO: Record segment info for later protection finalization */
@@ -859,6 +936,12 @@ bool remote_csoloader_load_and_resolve_entry(int pid, struct user_regs_struct *r
859936 }
860937 }
861938
939+ call_regs = regs_saved ;
940+
941+ args [0 ] = remote_fd ;
942+
943+ remote_call (pid , & call_regs , (uintptr_t )close_addr , libc_return_addr , args , 1 );
944+
862945 struct elf_dyn_info dinfo ;
863946 if (!elf_load_dyn_info (fd , & eh , phdr , & dinfo )) {
864947 LOGE ("Failed to load ELF dynamic info" );
@@ -914,34 +997,6 @@ bool remote_csoloader_load_and_resolve_entry(int pid, struct user_regs_struct *r
914997 remote_call (pid , & call_regs , (uintptr_t )mprotect_addr , libc_return_addr , args , 3 );
915998 }
916999
917- /* INFO: Some kernels drop names if string pointer invalidates.
918- We already have the ELF parsed, so look up symbol inline and use the helper. */
919- ElfW (Addr ) name_sym_value = 0 ;
920- if (!find_dynsym_value (fd , & dinfo , "k_library_name" , & name_sym_value )) {
921- LOGE ("Failed to resolve k_library_name from ELF dynsym" );
922-
923- free ((void * )needed_paths );
924- elf_dyn_info_destroy (& dinfo );
925- free (phdr );
926- close (fd );
927-
928- return false;
929- }
930-
931- call_regs = regs_saved ;
932-
933- uintptr_t name_ptr = (uintptr_t )load_bias + (uintptr_t )name_sym_value ;
934- if (!apply_vma_names (pid , & call_regs , (uintptr_t )prctl_addr , libc_return_addr , remote_base , map_size , name_ptr )) {
935- LOGE ("Failed to apply VMA names" );
936-
937- free ((void * )needed_paths );
938- elf_dyn_info_destroy (& dinfo );
939- free (phdr );
940- close (fd );
941-
942- return false;
943- }
944-
9451000 ElfW (Addr ) entry_value = 0 ;
9461001 if (!find_dynsym_value (fd , & dinfo , "entry" , & entry_value )) {
9471002 LOGE ("Failed to resolve entry from ELF dynsym" );
0 commit comments