diff --git a/sys/kern/kern_exec.pas b/sys/kern/kern_exec.pas index e19908a6..3f27089b 100644 --- a/sys/kern/kern_exec.pas +++ b/sys/kern/kern_exec.pas @@ -54,7 +54,9 @@ uses kern_resource, sys_event, kern_event, - machdep; + machdep, + kern_named_id, + kern_namedobj; function exec_alloc_args(args:p_image_args):Integer; begin @@ -501,7 +503,7 @@ function exec_check_permissions(imgp:p_image_params):Integer; var vp:p_vnode; attr:p_vattr; - error,writecount:Integer; + error:Integer; begin vp:=imgp^.vp; attr:=imgp^.attr; @@ -540,8 +542,7 @@ begin * Check number of open-for-writes on the file and deny execution * if there are any. } - writecount:=vp^.v_writecount; - if (writecount<>0) then Exit(ETXTBSY); + if (vp^.v_writecount<>0) then Exit(ETXTBSY); { * Call filesystem specific open routine (which does nothing in the @@ -553,147 +554,6 @@ begin Exit(error); end; -procedure scan_load_size(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer;var max_size,mx2_size:QWORD); -var - i:Integer; - use_mode_2mb:Boolean; - - size :QWORD; - vaddr :QWORD; - vaddr_lo:QWORD; - vaddr_hi:QWORD; -begin - max_size:=0; - mx2_size:=0; - - if (count<>0) then - For i:=0 to count-1 do - begin - if ((phdr^.p_type=PT_SCE_RELRO) or - (phdr^.p_type=PT_LOAD)) and - (phdr^.p_memsz<>0) then - begin - vaddr:=phdr^.p_vaddr; - - if (imgp^.image_header^.e_type=ET_SCE_DYNEXEC) then - begin - vaddr:=vaddr + QWORD(imgp^.reloc_base); - end; - - vaddr_lo:=vaddr and $ffffffffffffc000; - vaddr_hi:=phdr^.p_memsz + vaddr; - - size:=((vaddr_hi - vaddr_lo) + $3fff) and $ffffffffffffc000; - - max_size:=max_size + size; - - use_mode_2mb:=is_used_mode_2mb(phdr,0,budget_ptype_caller); - - if (use_mode_2mb) then - begin - vaddr_lo:=(vaddr_lo + $1fffff) and $ffffffffffe00000; - vaddr_hi:=(vaddr_lo + size ) and $ffffffffffe00000; - - size:=0; - if (vaddr_lo <= vaddr_hi) then - begin - size:=vaddr_hi - vaddr_lo; - end; - - mx2_size:=mx2_size + size; - end; - - end; - - Inc(phdr); - end; -end; - -function self_load_section(imgp:p_image_params; - id,vaddr,offset,memsz,filesz:QWORD; - prot:Byte; - use_mode_2mb:Boolean; - name:pchar):Integer; -var - map:vm_map_t; - vaddr_lo:QWORD; - vaddr_hi:QWORD; - base :Pointer; -begin - Result:=0; - - if (memsz0) then - begin - Writeln(StdErr,'[KERNEL] self_load_section: non-aligned segment ',id,', ',HexStr(vaddr,8)); - Exit(ENOEXEC); - end; - - vaddr_lo:=vaddr and $ffffffffffffc000; - vaddr_hi:=(memsz + vaddr + $3fff) and $ffffffffffffc000; - - if (use_mode_2mb) then - begin - vaddr_lo:=(vaddr + $1fffff) and $ffffffffffe00000; - vaddr_hi:=(vaddr + memsz + $3fff) and $ffffffffffe00000; - end; - - base:=Pointer(imgp^.image_header)+offset; - - map:=@g_vmspace.vm_map; - - vm_map_lock(map); - - //remove prev if exist - vm_map_delete(map,vaddr_lo,vaddr_hi); - - Result:=vm_map_insert(map,nil,0,vaddr_lo,vaddr_hi,VM_PROT_RW,prot or VM_PROT_RW,0); - if (Result<>0) then - begin - vm_map_unlock(map); - // - Writeln(StdErr,'[KERNEL] self_load_section: vm_map_insert failed ',id,', ',HexStr(vaddr,8)); - Exit(vm_mmap_to_errno(Result)); - end; - - vm_map_set_name_locked(map,vaddr_lo,vaddr_hi,name); - - Result:=copyout(base,Pointer(vaddr),filesz); - if (Result<>0) then - begin - vm_map_unlock(map); - // - Writeln(StdErr,'[KERNEL] self_load_section: copyout failed ', - id,', ',HexStr(base),'->',HexStr(vaddr,8),':',HexStr(filesz,8)); - readln; - Exit; - end; - - Result:=vm_map_protect(map,vaddr_lo,vaddr_hi,prot,False); - if (Result<>0) then - begin - vm_map_unlock(map); - // - Writeln(StdErr,'[KERNEL] self_load_section: vm_map_protect failed ',id,', ',HexStr(vaddr,8)); - Exit(vm_mmap_to_errno(Result)); - end; - - vm_map_unlock(map); -end; - - - function scan_load_sections(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer; var i:Integer; @@ -705,13 +565,14 @@ var data_addr :QWORD; text_addr :QWORD; text_size :QWORD; + p_memsz :QWORD; p_vaddr :QWORD; p_filesz :QWORD; p_offset :QWORD; - seg_addr:QWORD; - seg_size:QWORD; + addr:QWORD; + size:QWORD; p_type :Elf64_Word; p_flags :Byte; @@ -722,10 +583,10 @@ var begin Result:=0; - data_addr :=0; - text_addr :=0; total_size:=0; data_size :=0; + data_addr :=0; + text_addr :=0; text_size :=0; hdr:=imgp^.image_header; @@ -807,25 +668,25 @@ begin end; if (Result<>0) then Exit; - seg_addr:=(p_vaddr and QWORD($ffffffffffffc000)); - seg_size:=((p_vaddr and $3fff) + $3fff + phdr^.p_memsz) and QWORD($ffffffffffffc000); + addr:=(p_vaddr and QWORD($ffffffffffffc000)); + size:=((p_vaddr and $3fff) + $3fff + phdr^.p_memsz) and QWORD($ffffffffffffc000); if (p_type=PT_SCE_RELRO) then begin - imgp^.relro_addr:=Pointer(seg_addr); - imgp^.relro_size:=seg_size; + imgp^.relro_addr:=Pointer(addr); + imgp^.relro_size:=size; end else - if ((phdr^.p_flags and PF_X)<>0) and (text_size < seg_size) then + if ((phdr^.p_flags and PF_X)<>0) and (text_size < size) then begin - text_size:=seg_size; - text_addr:=seg_addr; + text_size:=size; + text_addr:=addr; end else begin - data_size:=seg_size; - data_addr:=seg_addr; + data_size:=size; + data_addr:=addr; end; - total_size:=total_size+seg_size; + total_size:=total_size+size; end; Inc(phdr); @@ -849,14 +710,14 @@ begin g_vmspace.vm_dsize:=data_size shr PAGE_SHIFT; g_vmspace.vm_daddr:=Pointer(data_addr); - seg_addr:=0; + addr:=0; if (hdr^.e_type=ET_SCE_DYNEXEC) then begin - seg_addr:=text_addr; + addr:=text_addr; end; - imgp^.entry_addr:=Pointer(seg_addr + hdr^.e_entry); - imgp^.reloc_base:=Pointer(seg_addr); + imgp^.entry_addr:=Pointer(addr + hdr^.e_entry); + imgp^.reloc_base:=Pointer(addr); auxargs:=AllocMem(SizeOf(t_elf64_auxargs)); @@ -875,53 +736,14 @@ begin MoveChar0(imgp^.execpath^,p_proc.prog_name,1024); - if (imgp^.reloc_base<>nil) and (imgp^.relro_size<>0) then + if (imgp^.relro_addr<>nil) and (imgp^.relro_size<>0) then begin - Result:=vm_map_protect(@g_vmspace.vm_map,QWORD(imgp^.reloc_base),QWORD(imgp^.reloc_base)+imgp^.relro_size,VM_PROT_READ,False); + Result:=vm_map_protect(@g_vmspace.vm_map,QWORD(imgp^.relro_addr),QWORD(imgp^.relro_addr)+imgp^.relro_size,VM_PROT_READ,False); Result:=vm_mmap_to_errno(Result); end; end; -function scan_dyn_offset(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer; -var - hdr:p_elf64_hdr; - p_offset:QWORD; - p_filesz:QWORD; - i:Integer; -begin - Result:=0; - - if (imgp^.dyn_id=-1) then Exit; - - hdr:=imgp^.image_header; - - p_offset:=phdr[imgp^.dyn_id].p_offset; - p_filesz:=phdr[imgp^.dyn_id].p_filesz; - - if (count<>0) then - For i:=0 to count-1 do - begin - - if (phdr[i].p_offset <= p_offset) and - (imgp^.dyn_id<>i) and - ( (p_filesz + p_offset) <= (phdr[i].p_offset + phdr[i].p_filesz)) then - begin - if (i<>-1) then - begin - imgp^.dyn_id :=i; - imgp^.dyn_offset:=imgp^.dyn_offset - phdr[i].p_offset; - if (hdr^.e_type<>ET_EXEC) then Exit(0); - Exit(ENOEXEC); - end; - break; - end; - - end; - - Result:=EINVAL; -end; - function dynlib_proc_initialize_step1(imgp:p_image_params):Integer; var lib:p_lib_info; @@ -1085,9 +907,13 @@ begin end; function dynlib_proc_initialize_step3(imgp:p_image_params):Integer; +label + _dyn_not_exist; var lib:p_lib_info; str:RawByteString; + entry:p_Objlist_Entry; + key:Integer; begin Result:=0; @@ -1096,9 +922,10 @@ begin //if (td_proc->sdk_version < 0x5000000) { // *(byte *)&dynlibs_info->bits = *(byte *)&dynlibs_info->bits | 0x20; //} - //if (imgp->dyn_exist == 0) goto _dyn_not_exist; - str:='/libkernel.sprx'; + if (imgp^.dyn_exist=0) then goto _dyn_not_exist; + + str:='libkernel.sprx'; lib:=preload_prx_modules(str); dynlibs_info.libkernel:=lib; @@ -1107,7 +934,7 @@ begin Writeln(StdErr,'preload_prx_modules:',str,' not loaded'); end; - str:='/libSceLibcInternal.sprx'; + str:='libSceLibcInternal.sprx'; lib:=preload_prx_modules(str); if (lib=nil) then @@ -1115,8 +942,73 @@ begin Writeln(StdErr,'preload_prx_modules:',str,' not loaded'); end; + lib:=TAILQ_FIRST(@dynlibs_info.lib_list); + while (lib<>nil) do + begin + entry:=AllocMem(SizeOf(Objlist_Entry)); + entry^.obj:=lib; + + TAILQ_INSERT_TAIL(@dynlibs_info.needed,entry,@entry^.link); + + Inc(lib^.ref_count); + + // + + entry:=AllocMem(SizeOf(Objlist_Entry)); + entry^.obj:=lib; + + TAILQ_INSERT_TAIL(@lib^.dagmembers,entry,@entry^.link); + + // + + entry:=AllocMem(SizeOf(Objlist_Entry)); + entry^.obj:=lib; + + TAILQ_INSERT_TAIL(@lib^.dldags,entry,@entry^.link); + + // + + lib:=TAILQ_NEXT(lib,@lib^.entry); + end; + + //dynlibs_info.sceKernelReportUnpatchedFunctionCall:=do_dlsym(dynlibs_info,dynlibs_info.libkernel,'sceKernelReportUnpatchedFunctionCall',nil,0); + //dynlibs_info.__freeze:=do_dlsym(dynlibs_info,dynlibs_info.libkernel,'__freeze','libkernel_sysc_se', 0); + //dynlibs_info.sysc_s00:=do_dlsym(dynlibs_info,dynlibs_info.libkernel,'sysc_s00','libkernel_sysc_se', 0); + //dynlibs_info.sysc_e00:=do_dlsym(dynlibs_info,dynlibs_info.libkernel,'sysc_e00','libkernel_sysc_se', 0); + + lib:=TAILQ_FIRST(@dynlibs_info.lib_list); + while (lib<>nil) do + begin + dynlib_initialize_pltgot_each(lib); + // + lib:=TAILQ_NEXT(lib,@lib^.entry); + end; + + imgp^.entry_addr:=dynlibs_info.libkernel^.entry_addr; + + _dyn_not_exist: + + lib:=TAILQ_FIRST(@dynlibs_info.lib_list); + while (lib<>nil) do + begin + + lib^.desc.free:=nil; + lib^.objt:=NAMED_DYNL; + lib^.name:=''; + + key:=-1; + if not id_name_new(@named_table,lib,@key) then + begin + Assert(False,'ID for PRX cannot be assigned.'); + end; + + lib^.id:=key; + id_release(lib); + + // + lib:=TAILQ_NEXT(lib,@lib^.entry); + end; - writeln; end; @@ -1171,11 +1063,11 @@ begin Exit(ENOEXEC); end; - exec_load_authinfo(imgp); + rtld_load_auth(imgp); if (hdr^.e_type=ET_SCE_REPLAY_EXEC) then begin - //(mmap_flags + 4) | 2; + p_proc.p_sce_replay_exec:=1; end; if (hdr^.e_type=ET_SCE_DYNEXEC) then @@ -1188,6 +1080,11 @@ begin imgp^.proc_param_addr :=reloc_base+QWORD(imgp^.proc_param_addr ); end; + if (hdr^.e_type=ET_EXEC) then + begin + Exit(ENOEXEC); + end; + if (imgp^.dyn_exist=0) then begin // @@ -1207,8 +1104,7 @@ begin max_size:=0; mx2_size:=0; - - scan_load_size(imgp,phdr,hdr^.e_phnum,max_size,mx2_size); + scan_load_size(imgp,phdr,hdr^.e_phnum,0,budget_ptype_caller,max_size,mx2_size); Result:=scan_load_sections(imgp,phdr,hdr^.e_phnum); if (Result<>0) then @@ -1404,7 +1300,7 @@ begin // vm_object_reference(imgp^.object); //end; - error:=exec_load_self(imgp); + error:=rtld_load_self(imgp); if (error<>0) then goto exec_fail_dealloc; p_proc.p_osrel:=0; @@ -1565,7 +1461,7 @@ exec_fail_dealloc: { * free various allocated resources } - exec_load_free(imgp); + rtld_free_self(imgp); if (imgp^.vp<>nil) then begin diff --git a/sys/kern/kern_namedobj.pas b/sys/kern/kern_namedobj.pas index 5457f04f..522925b3 100644 --- a/sys/kern/kern_namedobj.pas +++ b/sys/kern/kern_namedobj.pas @@ -22,6 +22,10 @@ procedure named_table_init; //SYSINIT function sys_namedobj_create(name:PChar;objp:Pointer;objt:Integer):Integer; function sys_namedobj_delete(id,objt:Integer):Integer; +const + NAMED_OBJT=$1000; + NAMED_DYNL=$2000; + implementation uses @@ -29,9 +33,6 @@ uses systm, kern_thr; -const - NAMED_OBJT=$1000; - procedure named_table_init; begin id_table_init(@named_table,1); diff --git a/sys/kern/kern_rtld.pas b/sys/kern/kern_rtld.pas index 6b511d35..53956373 100644 --- a/sys/kern/kern_rtld.pas +++ b/sys/kern/kern_rtld.pas @@ -172,9 +172,10 @@ function maxInt64(a,b:Int64):Int64; inline; function minInt64(a,b:Int64):Int64; inline; function get_elf_phdr(elf_hdr:p_elf64_hdr):p_elf64_phdr; inline; -procedure exec_load_free(imgp:p_image_params); -function exec_load_self(imgp:p_image_params):Integer; -procedure exec_load_authinfo(imgp:p_image_params); + +procedure rtld_free_self(imgp:p_image_params); +function rtld_load_self(imgp:p_image_params):Integer; +procedure rtld_load_auth(imgp:p_image_params); function is_used_mode_2mb(phdr:p_elf64_phdr;is_dynlib,budget_ptype_caller:Integer):Boolean; @@ -254,7 +255,7 @@ begin end; end; -procedure exec_load_free(imgp:p_image_params); +procedure rtld_free_self(imgp:p_image_params); begin FreeMem(imgp^.image_header); FreeMem(imgp^.image_self); @@ -263,7 +264,7 @@ begin imgp^.elf_size:=0; end; -function exec_load_self(imgp:p_image_params):Integer; +function rtld_load_self(imgp:p_image_params):Integer; Var vp:p_vnode; obj_size:Int64; @@ -395,6 +396,26 @@ begin fixup_offset_size(src_ofs,mem_size,obj_size); fixup_offset_size(dst_ofs,mem_size,MaxSeg); + if (src_ofs>=obj_size) then + begin + Assert(false,'src_ofs>=obj_size'); + end; + + if ((src_ofs+mem_size)>=obj_size) then + begin + Assert(false,'(src_ofs+mem_size)>=obj_size'); + end; + + if (dst_ofs>=MaxSeg) then + begin + Assert(false,'dst_ofs>=MaxSeg'); + end; + + if ((dst_ofs+mem_size)>=MaxSeg) then + begin + Assert(false,'(dst_ofs+mem_size)>=MaxSeg'); + end; + Move( (Pointer(self_hdr) +src_ofs)^, //src (Pointer(imgp^.image_header)+dst_ofs)^, //dst mem_size); //size @@ -410,7 +431,7 @@ begin end; -procedure exec_load_authinfo(imgp:p_image_params); +procedure rtld_load_auth(imgp:p_image_params); var hdr:p_elf64_hdr; authinfo:p_self_authinfo; diff --git a/sys/kern/kern_thr.pas b/sys/kern/kern_thr.pas index fe653e8a..c5890294 100644 --- a/sys/kern/kern_thr.pas +++ b/sys/kern/kern_thr.pas @@ -298,6 +298,7 @@ var p_osrel:Integer; p_sdk_version:Integer; + p_sce_replay_exec:Integer; p_nsignals:Int64; p_nvcsw :Int64; diff --git a/sys/kern/subr_dynlib.pas b/sys/kern/subr_dynlib.pas index ff13e3cb..b1bda119 100644 --- a/sys/kern/subr_dynlib.pas +++ b/sys/kern/subr_dynlib.pas @@ -10,7 +10,8 @@ uses mqueue, elf64, kern_thr, - kern_rtld; + kern_rtld, + kern_named_id; type p_rel_data=^t_rel_data; @@ -62,7 +63,7 @@ type end; p_lib_info=^t_lib_info; - t_lib_info=record + t_lib_info=object(t_id_named_desc) entry:TAILQ_ENTRY; lib_path :PAnsiChar; @@ -92,7 +93,7 @@ type tls_offset :QWORD; tls_align :QWORD; - pltgot:Pointer; + //pltgot:Pointer; needed :TAILQ_HEAD; //Needed_Entry lib_table :TAILQ_HEAD; //Lib_Entry @@ -117,6 +118,8 @@ type init_done :Integer; init_fini :Integer; textrel :Integer; + init_plt :Integer; + is_system :Integer; dldags :TAILQ_HEAD; //Objlist_Entry dagmembers:TAILQ_HEAD; //Objlist_Entry @@ -155,7 +158,7 @@ type link :TAILQ_ENTRY; dval :TLibraryValue; attr :WORD; - export:WORD; + import:WORD; end; p_dynlibs_info=^t_dynlibs_info; @@ -165,7 +168,7 @@ type libkernel :p_lib_info; obj_count :Integer; list_global:TAILQ_HEAD; //p_Objlist_Entry - needed :TAILQ_HEAD; //p_Needed_Entry + needed :TAILQ_HEAD; //p_Objlist_Entry init_list :TAILQ_HEAD; //p_Objlist_Entry fini_list :TAILQ_HEAD; //p_Objlist_Entry @@ -231,6 +234,17 @@ procedure dynlibs_add_obj(lib:p_lib_info); procedure init_relo_bits_process(lib:p_lib_info); +function scan_dyn_offset(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer; +procedure scan_load_size (imgp:p_image_params;phdr:p_elf64_phdr;count,dynlib,budget:Integer;var max_size,mx2_size:QWORD); + +function self_load_section(imgp:p_image_params; + id,vaddr,offset,memsz,filesz:QWORD; + prot:Byte; + use_mode_2mb:Boolean; + name:pchar):Integer; + +function dynlib_initialize_pltgot_each(obj:p_lib_info):Integer; + function do_load_object(path:pchar):p_lib_info; function preload_prx_modules(const path:RawByteString):p_lib_info; @@ -244,7 +258,20 @@ uses systm, vm, vmparam, - vm_map; + vm_map, + vm_mmap, + vm_object, + vuio, + vstat, + vfcntl, + vnode, + vmount, + vnamei, + vfs_lookup, + vfs_subr, + vnode_if, + _resource, + kern_resource; function scan_phdr(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer; var @@ -942,10 +969,10 @@ begin if (imgp^.dyn_exist=0) then Exit(EINVAL); - full_size:=sizeOf(t_rel_data)+1+ + full_size:=sizeOf(t_rel_data)+ AlignUp(imgp^.sce_dynlib_data_size,8)+ - AlignUp(imgp^.sce_comment_filesz,8)+ - strlen(imgp^.execpath); + AlignUp(imgp^.sce_comment_filesz ,8)+ + strlen(imgp^.execpath)+1; new^.rel_data:=AllocMem(full_size); @@ -972,7 +999,7 @@ begin dst:=dst+AlignUp(imgp^.sce_comment_filesz,8); end; - Move(imgp^.execpath^,dst^,sizeOf(t_rel_data)+1); + Move(imgp^.execpath^,dst^,strlen(imgp^.execpath)); new^.rel_data^.execpath:=dst; @@ -1127,6 +1154,7 @@ begin begin Exit(True); end; + entry:=TAILQ_NEXT(entry,@entry^.link); end; Result:=False; end; @@ -1145,7 +1173,7 @@ function Lib_new(d_tag:DWORD;d_val:QWORD):p_Lib_Entry; begin Result:=AllocMem(SizeOf(Lib_Entry)); QWORD(Result^.dval):=d_val; - Result^.export:=ord(d_tag=DT_SCE_IMPORT_LIB); + Result^.import:=ord(d_tag=DT_SCE_IMPORT_LIB); end; procedure initlist_add_objects(var fini_proc_list:TAILQ_HEAD; @@ -1527,11 +1555,677 @@ begin lib^.relo_bits_process:=AllocMem((count+7) div 8); end; +function scan_dyn_offset(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer; +var + p_offset:QWORD; + p_filesz:QWORD; + i:Integer; +begin + Result:=0; + + if (imgp^.dyn_id=-1) then Exit; + + p_offset:=phdr[imgp^.dyn_id].p_offset; + p_filesz:=phdr[imgp^.dyn_id].p_filesz; + + if (count<>0) then + For i:=0 to count-1 do + begin + + if (phdr[i].p_offset <= p_offset) and + (imgp^.dyn_id<>i) and + ( (p_filesz + p_offset) <= (phdr[i].p_offset + phdr[i].p_filesz)) then + begin + if (i<>-1) then + begin + imgp^.dyn_id :=i; + imgp^.dyn_offset:=imgp^.dyn_offset - phdr[i].p_offset; + Exit(0); + end; + break; + end; + + end; + + Result:=EINVAL; +end; + +procedure scan_load_size(imgp:p_image_params;phdr:p_elf64_phdr;count,dynlib,budget:Integer;var max_size,mx2_size:QWORD); +var + i:Integer; + use_mode_2mb:Boolean; + + size :QWORD; + vaddr :QWORD; + vaddr_lo:QWORD; + vaddr_hi:QWORD; +begin + max_size:=0; + mx2_size:=0; + + if (count<>0) then + For i:=0 to count-1 do + begin + if ((phdr^.p_type=PT_SCE_RELRO) or + (phdr^.p_type=PT_LOAD)) and + (phdr^.p_memsz<>0) then + begin + vaddr:=phdr^.p_vaddr; + + if (imgp^.image_header^.e_type=ET_SCE_DYNEXEC) then + begin + vaddr:=vaddr + QWORD(imgp^.reloc_base); + end; + + vaddr_lo:=vaddr and $ffffffffffffc000; + vaddr_hi:=phdr^.p_memsz + vaddr; + + size:=((vaddr_hi - vaddr_lo) + $3fff) and $ffffffffffffc000; + + max_size:=max_size + size; + + use_mode_2mb:=is_used_mode_2mb(phdr,dynlib,budget); + + if (use_mode_2mb) then + begin + vaddr_lo:=(vaddr_lo + $1fffff) and $ffffffffffe00000; + vaddr_hi:=(vaddr_lo + size ) and $ffffffffffe00000; + + size:=0; + if (vaddr_lo <= vaddr_hi) then + begin + size:=vaddr_hi - vaddr_lo; + end; + + mx2_size:=mx2_size + size; + end; + + end; + + Inc(phdr); + end; +end; + +function self_load_section(imgp:p_image_params; + id,vaddr,offset,memsz,filesz:QWORD; + prot:Byte; + use_mode_2mb:Boolean; + name:pchar):Integer; +var + map:vm_map_t; + vaddr_lo:QWORD; + vaddr_hi:QWORD; + base :Pointer; +begin + Result:=0; + + if (memsz0) then + begin + Writeln(StdErr,'[KERNEL] self_load_section: non-aligned segment ',id,', ',HexStr(vaddr,8)); + Exit(ENOEXEC); + end; + + vaddr_lo:=vaddr and $ffffffffffffc000; + vaddr_hi:=(memsz + vaddr + $3fff) and $ffffffffffffc000; + + if (use_mode_2mb) then + begin + vaddr_lo:=(vaddr + $1fffff) and $ffffffffffe00000; + vaddr_hi:=(vaddr + memsz + $3fff) and $ffffffffffe00000; + end; + + base:=Pointer(imgp^.image_header)+offset; + + map:=@g_vmspace.vm_map; + + vm_map_lock(map); + + //remove prev if exist + vm_map_delete(map,vaddr_lo,vaddr_hi); + + Result:=vm_map_insert(map,nil,0,vaddr_lo,vaddr_hi,VM_PROT_RW,prot or VM_PROT_RW,0); + if (Result<>0) then + begin + vm_map_unlock(map); + // + Writeln(StdErr,'[KERNEL] self_load_section: vm_map_insert failed ',id,', ',HexStr(vaddr,8)); + Exit(vm_mmap_to_errno(Result)); + end; + + vm_map_set_name_locked(map,vaddr_lo,vaddr_hi,name); + + Result:=copyout(base,Pointer(vaddr),filesz); + if (Result<>0) then + begin + vm_map_unlock(map); + // + Writeln(StdErr,'[KERNEL] self_load_section: copyout failed ', + id,', ',HexStr(base),'->',HexStr(vaddr,8),':',HexStr(filesz,8)); + readln; + Exit; + end; + + Result:=vm_map_protect(map,vaddr_lo,vaddr_hi,prot,False); + if (Result<>0) then + begin + vm_map_unlock(map); + // + Writeln(StdErr,'[KERNEL] self_load_section: vm_map_protect failed ',id,', ',HexStr(vaddr,8)); + Exit(vm_mmap_to_errno(Result)); + end; + + vm_map_unlock(map); +end; + +function is_system_path(path:pchar):Boolean; +var + f:RawByteString; +begin + f:='/'+p_proc.p_randomized_path; + Result:=StrLComp(pchar(f),path,Length(f))=0; +end; + +function is_libc_or_fios(path:pchar):Boolean; +var + f:RawByteString; +begin + f:=ExtractFileName(path); + f:=ChangeFileExt(f,''); + case f of + 'libc', + 'libSceFios2': + Result:=True; + else + Result:=False; + end; +end; + +function vm_reserved(map :vm_map_t; + addr :p_vm_offset_t; + size :vm_size_t):Integer; +begin + if (p_proc.p_sce_replay_exec<>0) then + begin + addr^:=$fc0000000; + end; + + Result:=_vm_mmap(map,addr,size,0,0,MAP_ANON or MAP_PRIVATE,OBJT_DEFAULT,nil,0); +end; + +function dynlib_load_sections(imgp:p_image_params;new:p_lib_info;phdr:p_elf64_phdr;count:Integer;delta:QWORD):Integer; +var + i:Integer; + + hdr:p_elf64_hdr; + + total_size:QWORD; + data_size :QWORD; + data_addr :QWORD; + text_addr :QWORD; + text_size :QWORD; + + p_memsz :QWORD; + p_vaddr :QWORD; + p_filesz :QWORD; + p_offset :QWORD; + + addr:QWORD; + size:QWORD; + + p_type :Elf64_Word; + p_flags :Byte; + _2mb_mode:Boolean; + used_mode_2m:Boolean; + + fname:RawByteString; +begin + Result:=0; + + fname:=ExtractFileName(imgp^.execpath); + + total_size:=0; + data_size :=0; + data_addr :=0; + text_addr :=0; + text_size :=0; + + if (budget_ptype_caller=0) then + begin + _2mb_mode:=((g_mode_2mb or 1)=3); + end else + begin + _2mb_mode:=False; + end; + + if (count<>0) then + For i:=0 to count-1 do + begin + p_type :=phdr^.p_type; + p_memsz:=phdr^.p_memsz; + + if ((p_type=PT_SCE_RELRO) or (p_type=PT_LOAD)) and (p_memsz<>0) then + begin + + p_flags:=VM_PROT_READ or VM_PROT_WRITE; + if (p_type<>PT_SCE_RELRO) then + begin + p_flags:=trans_prot(phdr^.p_flags); + end; + + p_vaddr:=delta+phdr^.p_vaddr; + + p_filesz:=phdr^.p_filesz; + p_offset:=phdr^.p_offset; + + if (p_type=PT_SCE_RELRO) and (budget_ptype_caller=0) then + begin + + if (_2mb_mode=false) then + begin + used_mode_2m:=false; + end else + begin + used_mode_2m:=is_used_mode_2mb(phdr,1,0); + end; + + Result:=self_load_section(imgp, + i, + p_vaddr, + p_offset, + p_memsz, + p_filesz, + p_flags, + used_mode_2m, + pchar(fname)); + + end else + begin + + if (_2mb_mode=false) then + begin + used_mode_2m:=false; + end else + begin + used_mode_2m:=is_used_mode_2mb(phdr,0,budget_ptype_caller); + end; + + Result:=self_load_section(imgp, + i, + p_vaddr, + p_offset, + p_memsz, + p_filesz, + p_flags, + used_mode_2m, + pchar(fname)); + end; + if (Result<>0) then Exit; + + addr:=(p_vaddr and QWORD($ffffffffffffc000)); + size:=((p_vaddr and $3fff) + $3fff + phdr^.p_memsz) and QWORD($ffffffffffffc000); + + if (p_type=PT_SCE_RELRO) then + begin + imgp^.relro_addr:=Pointer(addr); + imgp^.relro_size:=size; + end else + if ((phdr^.p_flags and PF_X)<>0) and (text_size < size) then + begin + text_size:=size; + text_addr:=addr; + end else + begin + data_size:=size; + data_addr:=addr; + end; + + total_size:=total_size+size; + end; + + Inc(phdr); + end; + + if (data_addr=0) and (data_size=0) then + begin + data_addr:=text_addr; + data_size:=text_size; + end; + + if (imgp^.relro_addr<>nil) and (imgp^.relro_size<>0) then + begin + Result:=vm_map_protect(@g_vmspace.vm_map,QWORD(imgp^.relro_addr),QWORD(imgp^.reloc_base)+imgp^.relro_size,VM_PROT_READ,False); + Result:=vm_mmap_to_errno(Result); + if (Result<>0) then Exit; + end; + + addr:=imgp^.min_addr; + + imgp^.dyn_vaddr :=Pointer(imgp^.dyn_vaddr )+addr; + imgp^.entry_addr :=Pointer(imgp^.entry_addr )+addr; + imgp^.tls_init_addr:=Pointer(imgp^.tls_init_addr)+addr; + + if (imgp^.eh_frame_hdr_addr<>nil) then + begin + imgp^.eh_frame_hdr_addr:=Pointer(imgp^.eh_frame_hdr_addr)+addr; + end; + + if (imgp^.module_param_addr<>nil) then + begin + imgp^.module_param_addr:=Pointer(imgp^.module_param_addr)+addr; + end; + + if (elf64_get_eh_frame_info(new^.eh_frame_hdr_addr, + new^.eh_frame_hdr_size, + delta, + text_size + text_addr, + @new^.eh_frame_addr, + @new^.eh_frame_size)<>0) then + begin + new^.eh_frame_addr:=nil; + new^.eh_frame_size:=0; + end; + + hdr:=imgp^.image_header; + + new^.map_base :=Pointer(addr); + new^.map_size :=imgp^.max_addr - imgp^.min_addr; + new^.text_size :=text_size; + new^.data_addr :=Pointer(data_addr); + new^.data_size :=data_size; + new^.relocbase :=Pointer(addr); + new^.entry_addr :=Pointer(delta + hdr^.e_entry); + new^.module_param:=imgp^.module_param_addr; + new^.relro_addr :=imgp^.relro_addr; + new^.relro_size :=imgp^.relro_size; + +end; + function self_load_shared_object(path:pchar;new:p_lib_info):Integer; +label + _fail_dealloc; +var + nd:t_nameidata; + error:Integer; + budget:Integer; + + image_params:t_image_params; + imgp:p_image_params; + attr:t_vattr; + vp:p_vnode; + + hdr :p_elf64_hdr; + phdr:p_elf64_phdr; + + map:vm_map_t; + + addr,delta:QWORD; begin Result:=-1; + if (path=nil) then Exit; - ////////// + error:=0; + imgp:=@image_params; + image_params:=Default(t_image_params); + + attr:=Default(t_vattr); + imgp^.attr:=@attr; + imgp^.execpath:=path; + + NDINIT(@nd, LOOKUP, ISOPEN or LOCKLEAF or FOLLOW or SAVENAME or MPSAFE or AUDITVNODE1, UIO_SYSSPACE, path, curkthread); + + error:=nd_namei(@nd); + if (error<>0) then + begin + if (error<>EACCES) then Exit(error); + Writeln(StdErr,'self_load_shared_object:','namei() error (path=',path,')'); + Exit(error); + end; + + vp:=nd.ni_vp; + imgp^.vp:=vp; + + { Get file attributes } + error:=VOP_GETATTR(vp, imgp^.attr); + if (error<>0) then + begin + NDFREE(@nd, NDF_ONLY_PNBUF); + Exit(error); + end; + + if ((p_mount(vp^.v_mount)^.mnt_flag and MNT_NOEXEC)<>0) or + ((attr.va_mode and (S_IXUSR or S_IXGRP or S_IXOTH))=0) or + (attr.va_type<>VREG) then + begin + NDFREE(@nd, NDF_ONLY_PNBUF); + Writeln(StdErr,'self_load_shared_object:','mount flag / attribute error (path=',path,')'); + Exit(EACCES); + end; + + if (attr.va_size<32) then + begin + NDFREE(@nd, NDF_ONLY_PNBUF); + Exit(ENOEXEC); + end; + + error:=VOP_ACCESS(vp, VEXEC); + if (error<>0) then + begin + NDFREE(@nd, NDF_ONLY_PNBUF); + Writeln(StdErr,'self_load_shared_object:','VOP_ACCESS() error (path=',path,')'); + Exit(error); + end; + + if (vp^.v_writecount<>0) then + begin + NDFREE(@nd, NDF_ONLY_PNBUF); + Exit(ETXTBSY); + end; + + error:=VOP_OPEN(vp, FREAD, nil); + if (error<>0) then + begin + NDFREE(@nd, NDF_ONLY_PNBUF); + Writeln(StdErr,'self_load_shared_object:','VOP_OPEN() error (path=',path,')'); + Exit(error); + end; + + error:=rtld_load_self(imgp); + if (error<>0) then goto _fail_dealloc; + + hdr:=imgp^.image_header; + + if (hdr=nil) then Exit(EINVAL); + + Case hdr^.e_type of + ET_SCE_DYNAMIC: + else + begin + Writeln(StdErr,'self_load_shared_object:',imgp^.execpath,' Unsupported ELF e_type:',HexStr(hdr^.e_type,4)); + error:=ENOEXEC; + goto _fail_dealloc; + end; + end; + + budget:=budget_ptype_caller; + + if is_system_path(path) then + begin + if not is_libc_or_fios(path) then + begin + budget:=2; + end; + end; + + imgp^.hdr_e_type:=hdr^.e_type; + + phdr:=get_elf_phdr(hdr); + + error:=scan_phdr(imgp,phdr,hdr^.e_phnum); + if (error<>0) then + begin + Writeln(StdErr,'self_load_shared_object:','found illegal segment header in ',imgp^.execpath); + goto _fail_dealloc; + end; + + if (imgp^.dyn_exist=0) then + begin + Writeln(StdErr,'self_load_shared_object:','illegal ELF file image',imgp^.execpath); + error:=ENOEXEC; + goto _fail_dealloc; + end; + + rtld_load_auth(imgp); + + new^.tls_size :=imgp^.tls_size; + new^.tls_align :=imgp^.tls_align; + new^.tls_init_size :=imgp^.tls_init_size; + new^.tls_init_addr :=imgp^.tls_init_addr; + new^.eh_frame_hdr_addr:=imgp^.eh_frame_hdr_addr; + new^.eh_frame_hdr_size:=imgp^.eh_frame_hdr_size; + + error:=scan_dyn_offset(imgp,phdr,hdr^.e_phnum); + if (error<>0) then + begin + goto _fail_dealloc; + end; + + addr:=ET_DYN_LOAD_ADDR_USR; + if (budget=2) then + begin + addr:=ET_DYN_LOAD_ADDR_SYS; + end; + + map:=@g_vmspace.vm_map; + + error:=vm_reserved(map,@addr,imgp^.max_addr-imgp^.min_addr); + if (error<>0) then + begin + Writeln(StdErr,'self_load_shared_object:','failed to allocate VA for ',imgp^.execpath); + goto _fail_dealloc; + end; + + delta:=addr-imgp^.min_addr; + imgp^.min_addr:=addr; + imgp^.max_addr:=imgp^.max_addr+delta; + + new^.tls_init_addr :=new^.tls_init_addr +delta; + new^.eh_frame_hdr_addr:=new^.eh_frame_hdr_addr+delta; + + error:=dynlib_load_sections(imgp,new,phdr,hdr^.e_phnum,delta); + if (error<>0) then + begin + goto _fail_dealloc; + end; + + if (budget=2) then + begin + new^.is_system:=1; + end; + + error:=acquire_per_file_info_obj(imgp,new); + if (error<>0) then + begin + Writeln(StdErr,'self_load_shared_object:','acquire_per_file_info_obj()=',error); + goto _fail_dealloc; + end; + + _fail_dealloc: + rtld_free_self(imgp); + NDFREE(@nd, NDF_ONLY_PNBUF); + VOP_CLOSE(vp, FREAD); + vput(vp); + + Exit(error); +end; + +function dynlib_initialize_pltgot_each(obj:p_lib_info):Integer; +var + map:vm_map_t; + addr:Pointer; + entry:p_elf64_rela; + + kaddr:QWORD; + + i,count,err:Integer; +begin + Result:=0; + + if (obj^.init_plt<>0) then Exit; + + map:=@g_vmspace.vm_map; + + addr:=obj^.relro_addr; + + if (addr<>nil) and (obj^.relro_size<>0) then + begin + Result:=vm_map_protect(map,QWORD(addr),QWORD(addr)+obj^.relro_size,VM_PROT_RW,False); + if (Result<>0) then + begin + Writeln(StdErr,'change_relro_protection:','failed to make RELRO segment writable.'); + Exit; + end; + end; + + entry:=obj^.rel_data^.pltrela_addr; + count:=obj^.rel_data^.pltrela_size div SizeOf(elf64_rela); + + if (entry<>nil) and (count<>0) then + For i:=0 to count-1 do + begin + kaddr:=i or QWORD($effffffe00000000); + + addr:=Pointer(obj^.relocbase) + entry^.r_offset; + + if ( + (addr < obj^.data_addr) or + ((obj^.data_addr + obj^.data_size) < (addr + 8)) + ) and + ( (obj^.relro_addr=nil) or + (obj^.relro_addr>addr) or + (obj^.relro_size=0) or + ((obj^.relro_size + obj^.relro_addr) < (addr + 8)) + ) then + begin + Result:=ENOEXEC; + Break; + end; + + err:=copyout(@kaddr,addr,SizeOf(Pointer)); + if (err<>0) then + begin + Writeln(StdErr,'dynlib_initialize_pltgot_each:','ERROR in .pltrela: where=0x',HexStr(addr)); + Result:=ENOEXEC; + Break; + end; + + Inc(entry); + end; + + addr:=obj^.relro_addr; + + if (addr<>nil) and (obj^.relro_size<>0) then + begin + err:=vm_map_protect(map,QWORD(addr),QWORD(addr)+obj^.relro_size,VM_PROT_READ,False); + if (err<>0) then + begin + Writeln(StdErr,'change_relro_protection:','failed to make RELRO segment writable.'); + Exit; + end; + end; + + obj^.init_plt:=1; end; function do_load_object(path:pchar):p_lib_info; @@ -1605,7 +2299,7 @@ begin goto _error; end; - //err:=dynlib_initialize_pltgot_each(new); + err:=dynlib_initialize_pltgot_each(new); if (err<>0) then begin Writeln(StdErr,'do_load_object:','dynlib_initialize_pltgot_each() failed rv=',err); @@ -1665,10 +2359,6 @@ begin end; fname:=path; - if (fname[1]='/') then //relative? - begin - fname:=p_proc.p_randomized_path+fname; - end; if rtld_file_exists(pchar(fname)) then goto _do_load; @@ -1678,6 +2368,24 @@ begin fname:=ChangeFileExt(fname,'.prx'); if rtld_file_exists(pchar(fname)) then goto _do_load; + + fname:=path; + + if (fname[1]<>'/') then + begin + fname:='/'+fname; + end; + fname:=p_proc.p_randomized_path+fname; + + if rtld_file_exists(pchar(fname)) then goto _do_load; + + fname:=ChangeFileExt(fname,'.sprx'); + if rtld_file_exists(pchar(fname)) then goto _do_load; + + fname:=ChangeFileExt(fname,'.prx'); + if rtld_file_exists(pchar(fname)) then goto _do_load; + + Exit(nil); _do_load: diff --git a/sys/vm/vm_mmap.pas b/sys/vm/vm_mmap.pas index 9b48bd96..22efeeb8 100644 --- a/sys/vm/vm_mmap.pas +++ b/sys/vm/vm_mmap.pas @@ -5,6 +5,11 @@ unit vm_mmap; interface +uses + vm, + vm_map, + vm_object; + type p_query_memory_prot=^t_query_memory_prot; t_query_memory_prot=packed record @@ -30,17 +35,24 @@ function sys_query_memory_protection(addr:Pointer;info:Pointer):Integer; function vm_mmap_to_errno(rv:Integer):Integer; inline; +function _vm_mmap(map :vm_map_t; + addr :p_vm_offset_t; + size :vm_size_t; + prot :vm_prot_t; + maxprot :vm_prot_t; + flags :Integer; + handle_type:objtype_t; + handle :Pointer; + foff :vm_ooffset_t):Integer; + implementation uses vcapability, - vm, - vm_map, systm, errno, kern_thr, vmparam, - vm_object, _resource, kern_resource, kern_mtx,