diff --git a/sys/fs/ufs/ufs.pas b/sys/fs/ufs/ufs.pas index 0ff83bd8..e3bf533d 100644 --- a/sys/fs/ufs/ufs.pas +++ b/sys/fs/ufs/ufs.pas @@ -423,13 +423,11 @@ begin if (mp^.mnt_optnew=nil) then Exit(EINVAL); if (vfs_getopt(mp^.mnt_optnew, 'from', @path, @plen)<>0) then Exit(EINVAL); if (path=nil) then Exit(EINVAL); - if (plen=2) then + + while (plen>0) and ((path[0]='/') or (path[0]='\')) do begin - if (path[0]='/') or (path[0]='\') then - begin - path[0]:=#0; - plen:=1; - end; + Inc(path); + Dec(plen); end; end; diff --git a/sys/kern/kern_exec.pas b/sys/kern/kern_exec.pas index fe96354a..e19908a6 100644 --- a/sys/kern/kern_exec.pas +++ b/sys/kern/kern_exec.pas @@ -6,12 +6,14 @@ unit kern_exec; interface uses + sysutils, mqueue, kern_thr, vnode, vuio, vcapability, elf64, + kern_rtld, subr_dynlib; function exec_alloc_args(args:p_image_args):Integer; @@ -613,6 +615,7 @@ function self_load_section(imgp:p_image_params; use_mode_2mb:Boolean; name:pchar):Integer; var + map:vm_map_t; vaddr_lo:QWORD; vaddr_hi:QWORD; base :Pointer; @@ -648,23 +651,28 @@ begin base:=Pointer(imgp^.image_header)+offset; - vm_map_lock(@g_vmspace.vm_map); + map:=@g_vmspace.vm_map; - Result:=vm_map_insert(@g_vmspace.vm_map,nil,0,vaddr_lo,vaddr_hi,VM_PROT_RW,prot or VM_PROT_RW,0); + 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(@g_vmspace.vm_map); + 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(@g_vmspace.vm_map,vaddr_lo,vaddr_hi,name); + 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(@g_vmspace.vm_map); + vm_map_unlock(map); // Writeln(StdErr,'[KERNEL] self_load_section: copyout failed ', id,', ',HexStr(base),'->',HexStr(vaddr,8),':',HexStr(filesz,8)); @@ -672,16 +680,16 @@ begin Exit; end; - Result:=vm_map_protect(@g_vmspace.vm_map,vaddr_lo,vaddr_hi,prot,False); + Result:=vm_map_protect(map,vaddr_lo,vaddr_hi,prot,False); if (Result<>0) then begin - vm_map_unlock(@g_vmspace.vm_map); + 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(@g_vmspace.vm_map); + vm_map_unlock(map); end; @@ -1012,8 +1020,6 @@ var init_proc_addr:Pointer; fini_proc_addr:Pointer; - - count:Integer; begin Result:=0; @@ -1024,8 +1030,7 @@ begin if (imgp^.dyn_exist=0) then begin - TAILQ_INSERT_TAIL(@dynlibs_info.lib_list,lib,@lib^.entry); - Inc(dynlibs_info.obj_count); + dynlibs_add_obj(lib); Exit; end; @@ -1036,18 +1041,9 @@ begin Exit; end; - if (lib^.rel_data=nil) then - begin - count:=0; - end else - begin - count:=(lib^.rel_data^.pltrela_size div sizeof(elf64_rela))+(lib^.rel_data^.rela_size div sizeof(elf64_rela)); - end; + init_relo_bits_process(lib); - lib^.relo_bits_process:=AllocMem((count+7) div 8); - - TAILQ_INSERT_TAIL(@dynlibs_info.lib_list,lib,@lib^.entry); - Inc(dynlibs_info.obj_count); + dynlibs_add_obj(lib); init_proc_addr:=lib^.init_proc_addr; fini_proc_addr:=lib^.fini_proc_addr; @@ -1088,6 +1084,41 @@ begin end; end; +function dynlib_proc_initialize_step3(imgp:p_image_params):Integer; +var + lib:p_lib_info; + str:RawByteString; +begin + Result:=0; + + lib:=nil; + + //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'; + lib:=preload_prx_modules(str); + dynlibs_info.libkernel:=lib; + + if (lib=nil) then + begin + Writeln(StdErr,'preload_prx_modules:',str,' not loaded'); + end; + + str:='/libSceLibcInternal.sprx'; + lib:=preload_prx_modules(str); + + if (lib=nil) then + begin + Writeln(StdErr,'preload_prx_modules:',str,' not loaded'); + end; + + + writeln; +end; + function exec_self_imgact(imgp:p_image_params):Integer; var @@ -1497,6 +1528,8 @@ begin PROC_UNLOCK(); + dynlib_proc_initialize_step3(imgp); + { Set values passed into the program in registers. } exec_setregs(td, QWORD(imgp^.entry_addr), QWORD(stack_base)); diff --git a/sys/kern/kern_rtld.pas b/sys/kern/kern_rtld.pas new file mode 100644 index 00000000..6b511d35 --- /dev/null +++ b/sys/kern/kern_rtld.pas @@ -0,0 +1,538 @@ +unit kern_rtld; + +{$mode ObjFPC}{$H+} +{$CALLING SysV_ABI_CDecl} + +interface + +uses + sysutils, + kern_thr, + vfile, + vnode, + vm_object, + vuio, + elf64; + +const + AT_NULL = 0; // Terminates the vector. + AT_IGNORE = 1; // Ignored entry. + AT_EXECFD = 2; // File descriptor of program to load. + AT_PHDR = 3; // Program header of program already loaded. + AT_PHENT = 4; // Size of each program header entry. + AT_PHNUM = 5; // Number of program header entries. + AT_PAGESZ = 6; // Page size in bytes. + AT_BASE = 7; // Interpreter's base address. + AT_FLAGS = 8; // Flags (unused for i386). + AT_ENTRY = 9; // Where interpreter should transfer control. + AT_NOTELF =10; // Program is not ELF ?? + AT_UID =11; // Real uid. + AT_EUID =12; // Effective uid. + AT_GID =13; // Real gid. + AT_EGID =14; // Effective gid. + AT_EXECPATH =15; // Path to the executable. + AT_CANARY =16; // Canary for SSP + AT_CANARYLEN =17; // Length of the canary. + AT_OSRELDATE =18; // OSRELDATE. + AT_NCPUS =19; // Number of CPUs. + AT_PAGESIZES =20; // Pagesizes. + AT_PAGESIZESLEN=21; // Number of pagesizes. + AT_TIMEKEEP =22; // Pointer to timehands. + AT_STACKPROT =23; // Initial stack protection. + + AT_COUNT =24; // Count of defined aux entry types. + + ARG_MAX=262144; // max bytes for an exec function + + ps_arg_cache_limit=$400; + +type + p_ps_strings=^t_ps_strings; + t_ps_strings=packed record + ps_argvstr :ppchar; //first of 0 or more argument string + ps_nargvstr:Integer; //the number of argument strings + _align1 :Integer; // + ps_envstr :ppchar; //first of 0 or more environment strings + ps_nenvstr :Integer; //the number of environment strings + _align2 :Integer; // + end; + {$IF sizeof(t_ps_strings)<>32}{$STOP sizeof(t_ps_strings)<>32}{$ENDIF} + + p_image_args=^t_image_args; + t_image_args=packed record + buf :PChar; //pointer to string buffer + begin_argv :PChar; //beginning of argv in buf + begin_envv :PChar; //beginning of envv in buf + endp :PChar; //current `end' pointer of arg & env strings + fname :PChar; //pointer to filename of executable (system space) + fname_buf :PChar; //pointer to optional malloc(M_TEMP) buffer + stringspace:Integer; //space left in arg & env buffer + argc :Integer; //count of argument strings + envc :Integer; //count of environment strings + fd :Integer; //file descriptor of the executable + end; + + p_elf64_auxargs=^t_elf64_auxargs; + t_elf64_auxargs=packed record + execfd:Int64; + phdr :QWORD; + phent :QWORD; + phnum :QWORD; + pagesz:QWORD; + base :QWORD; + flags :QWORD; + entry :QWORD; + end; + + p_authinfo=^t_authinfo; + t_authinfo=packed record + app_type_id:QWORD; + app_flags :QWORD; + app_cap :QWORD; + unknow1 :array[0..1] of QWORD; + s_prog_attr:QWORD; + unknow2 :array[0..10] of QWORD; + end; + {$IF sizeof(t_authinfo)<>136}{$STOP sizeof(t_authinfo)<>136}{$ENDIF} + + p_image_params=^t_image_params; + t_image_params=packed record + vp :p_vnode; + obj :vm_object_t; + attr :p_vattr; + image_self :p_self_header; + image_header:p_elf64_hdr; + entry_addr :Pointer; + reloc_base :Pointer; + opened :Integer; + elf_size :Integer; + auxargs :p_elf64_auxargs; + auxarg_size :QWORD; + args :p_image_args; + execpath :PChar; + execpathp :Pointer; + freepath :PChar; + canary :Pointer; + pagesizes :Pointer; + canarylen :Integer; + pagesizeslen:Integer; + + dyn_vaddr:p_elf64_dyn; + + tls_size :QWORD; + tls_align :QWORD; + tls_init_size:QWORD; + tls_init_addr:Pointer; + + eh_frame_hdr_addr:Pointer; + eh_frame_hdr_size:QWORD; + + authinfo:t_authinfo; + + proc_param_addr:pSceProcParam; + proc_param_size:QWORD; + + module_param_addr:psceModuleParam; + module_param_size:QWORD; + + dyn_id :Integer; + sce_dynlib_data_id:Integer; + sce_comment_id :Integer; + dyn_exist :Integer; + + dyn_offset :QWORD; + dyn_filesz :QWORD; + + sce_dynlib_data_addr:QWORD; + sce_dynlib_data_size:QWORD; + + sce_comment_offset :QWORD; + sce_comment_filesz :QWORD; + + min_addr:QWORD; + max_addr:QWORD; + + relro_addr:Pointer; + relro_size:QWORD; + + hdr_e_type:Integer; + end; + +const + M2MB_NOTDYN_FIXED=0; //Default =0 (ATTRIBUTE2:0x00000) + M2MB_DISABLE =1; //NotUsed =32768 (ATTRIBUTE2:0x08000) + M2MB_READONLY =2; //Text_rodata=65536 (ATTRIBUTE2:0x10000) + M2MB_ENABLE =3; //All_section=98304 (ATTRIBUTE2:0x18000) + + g_self_fixed:Integer=0; + g_mode_2mb :Integer=M2MB_NOTDYN_FIXED; + budget_ptype_caller:Integer=0; + +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); + +function is_used_mode_2mb(phdr:p_elf64_phdr;is_dynlib,budget_ptype_caller:Integer):Boolean; + +function rtld_dirname(path,bname:pchar):Integer; +function rtld_file_exists(path:pchar):Boolean; + +implementation + +uses + errno, + vnamei, + vfs_lookup, + vfs_subr, + vnode_if; + +function maxInt64(a,b:Int64):Int64; inline; +begin + if (a>b) then Result:=a else Result:=b; +end; + +function minInt64(a,b:Int64):Int64; inline; +begin + if (a0) then + begin + Result:=ENOEXEC; + end; + end; +end; + +procedure exec_load_free(imgp:p_image_params); +begin + FreeMem(imgp^.image_header); + FreeMem(imgp^.image_self); + imgp^.image_header:=nil; + imgp^.image_self:=nil; + imgp^.elf_size:=0; +end; + +function exec_load_self(imgp:p_image_params):Integer; +Var + vp:p_vnode; + obj_size:Int64; + n,s:Int64; + Magic:DWORD; + i,count:Integer; + self_hdr :p_self_header; + self_segs:p_self_segment; + elf_hdr :p_elf64_hdr; + elf_phdr :p_elf64_phdr; + MinSeg :Int64; + MaxSeg :Int64; + src_ofs :Int64; + dst_ofs :Int64; + mem_size :Int64; +begin + Result:=0; + + if (imgp=nil) then Exit(EINVAL); + + vp:=imgp^.vp; + obj_size:=imgp^.attr^.va_size; + + if (obj_size=0) then Exit(ENOEXEC); + + Result:=kread(vp,@Magic,SizeOf(DWORD),0); + if (Result<>0) then Exit; + + case Magic of + ELFMAG: //elf64 + begin + elf_hdr:=AllocMem(obj_size); + + Result:=kread(vp,elf_hdr,obj_size,0); + if (Result<>0) then + begin + FreeMem(elf_hdr); + Exit; + end; + + imgp^.image_header:=elf_hdr; + imgp^.image_self :=nil; + imgp^.elf_size :=obj_size; + end; + SELF_MAGIC: //self + begin + self_hdr:=AllocMem(obj_size); + + Result:=kread(vp,self_hdr,obj_size,0); + if (Result<>0) then + begin + FreeMem(self_hdr); + Exit; + end; + + if (self_hdr^.File_size>obj_size) then + begin + FreeMem(self_hdr); + Exit(EFAULT); + end; + + count:=self_hdr^.Num_Segments; + + if (count=0) then + begin + FreeMem(self_hdr); + Exit(ENOEXEC); + end; + + self_segs:=Pointer(self_hdr+1); + + For i:=0 to count-1 do + if ((self_segs[i].flags and (SELF_PROPS_ENCRYPTED or SELF_PROPS_COMPRESSED))<>0) then + begin + Writeln(StdErr,'exec_load_self:',imgp^.execpath,'is encrypted!'); + FreeMem(self_hdr); + Exit(ENOEXEC); + end; + + elf_hdr:=Pointer(self_segs)+(count*SizeOf(t_self_segment)); + + elf_phdr:=get_elf_phdr(elf_hdr); + + MinSeg:=High(Int64); + MaxSeg:=0; + + count:=self_hdr^.Num_Segments; + + For i:=0 to count-1 do + if ((self_segs[i].flags and SELF_PROPS_BLOCKED)<>0) then + begin + s:=SELF_SEGMENT_INDEX(self_segs[i].flags); + s:=elf_phdr[s].p_offset; + MinSeg:=MinInt64(s,MinSeg); + s:=s+minInt64(self_segs[i].filesz,self_segs[i].filesz); + MaxSeg:=MaxInt64(s,MaxSeg); + end; + + if (MinSeg>MaxSeg) then + begin + FreeMem(self_hdr); + Exit(EFAULT); + end; + + imgp^.image_header:=AllocMem(MaxSeg); + imgp^.elf_size :=MaxSeg; + + //elf_hdr part + n:=ptruint(elf_hdr)-ptruint(self_hdr); //offset to hdr + s:=self_hdr^.Header_Size+self_hdr^.Meta_size; //offset to end + s:=MinInt64(obj_size,s); //min size + s:=MaxInt64(s,n)-n; //get size + + //first page + Move(elf_hdr^,imgp^.image_header^,s); + + count:=self_hdr^.Num_Segments; + + For i:=0 to count-1 do + if ((self_segs[i].flags and SELF_PROPS_BLOCKED)<>0) then + begin + s:=SELF_SEGMENT_INDEX(self_segs[i].flags); + + mem_size:=minInt64(self_segs[i].filesz,self_segs[i].memsz); + + src_ofs:=self_segs[i].offset; //start offset + dst_ofs:=elf_phdr[s].p_offset; //start offset + + fixup_offset_size(src_ofs,mem_size,obj_size); + fixup_offset_size(dst_ofs,mem_size,MaxSeg); + + Move( (Pointer(self_hdr) +src_ofs)^, //src + (Pointer(imgp^.image_header)+dst_ofs)^, //dst + mem_size); //size + end; + + imgp^.image_self:=self_hdr; + end; + else + begin + Exit(ENOEXEC); + end; + end; + +end; + +procedure exec_load_authinfo(imgp:p_image_params); +var + hdr:p_elf64_hdr; + authinfo:p_self_authinfo; + s:ptruint; +begin + if (imgp=nil) then Exit; + + imgp^.authinfo:=Default(t_authinfo); + imgp^.authinfo.app_type_id:=QWORD($3100000000000001); + + if (imgp^.image_header=nil) then Exit; + if (imgp^.image_self =nil) then Exit; + + hdr:=imgp^.image_header; + s:=SizeOf(t_self_header); + s:=s+(imgp^.image_self^.Num_Segments*SizeOf(t_self_segment)); + s:=s+get_elf_phdr_offset(hdr); + s:=s+(hdr^.e_phnum*SizeOf(elf64_phdr)); + s:=AlignUp(s,SELF_SEGMENT_BLOCK_ALIGNMENT); + + authinfo:=Pointer(Pointer(imgp^.image_self)+s); + + imgp^.authinfo.app_type_id:=authinfo^.AuthorityID; +end; + +function is_used_mode_2mb(phdr:p_elf64_phdr;is_dynlib,budget_ptype_caller:Integer):Boolean; +var + flag_write:Integer; +begin + Result:=False; + + if (budget_ptype_caller=0) then + begin + flag_write:=2; + if (phdr^.p_type<>PT_SCE_RELRO) then + begin + flag_write:=phdr^.p_flags and 2; + end; + + case g_mode_2mb of + M2MB_NOTDYN_FIXED:Result:=(is_dynlib=0) and (g_self_fixed<>0); + M2MB_READONLY :Result:=(flag_write=0); + M2MB_ENABLE :Result:=True; + else; + end; + + end; +end; + +function rtld_dirname(path,bname:pchar):Integer; +var + endp:pchar; +begin + Result:=0; + + { Empty or NULL string gets treated as "." } + if (path=nil) or (path^=#0) then + begin + bname[0]:='.'; + bname[1]:=#0; + Exit(0); + end; + + { Strip trailing slashes } + endp:=path + strlen(path) - 1; + while (endp > path) and ((endp^='/') or (endp^='\')) do Dec(endp); + + { Find the start of the dir } + while (endp > path) and ((endp^<>'/') and (endp^<>'\')) do Dec(endp); + + { Either the dir is "/" or there are no slashes } + if (endp=path) then + begin + if ((endp^='/') or (endp^='\')) then + begin + bname[0]:='/'; + end else + begin + bname[0]:='.'; + end; + bname[1]:=#0; + Exit(0); + end else + begin + repeat + Dec(endp); + until not ((endp > path) and ((endp^='/') or (endp^='\'))); + end; + + if ((endp - path + 2) > PATH_MAX) then + begin + Writeln(StdErr,'Filename is too long:',path); + Exit(-1); + end; + + Move(path^, bname^, endp - path + 1); + bname[endp - path + 1]:=#0; + + Result:=0; +end; + +function rtld_file_exists(path:pchar):Boolean; +var + nd:t_nameidata; + error:Integer; +begin + Result:=False; + if (path=nil) then Exit; + + NDINIT(@nd,LOOKUP,LOCKLEAF or FOLLOW or SAVENAME or MPSAFE, UIO_SYSSPACE, path, curkthread); + + error:=nd_namei(@nd); + + if (error=0) then + begin + NDFREE(@nd, NDF_ONLY_PNBUF); + vput(nd.ni_vp); + Exit(True); + end; + + NDFREE(@nd, NDF_ONLY_PNBUF); +end; + +end. + diff --git a/sys/kern/kern_thr.pas b/sys/kern/kern_thr.pas index 6b599b7f..fe653e8a 100644 --- a/sys/kern/kern_thr.pas +++ b/sys/kern/kern_thr.pas @@ -303,8 +303,9 @@ var p_nvcsw :Int64; p_nivcsw :Int64; - p_comm :array[0..MAXCOMLEN] of AnsiChar; - prog_name:array[0..1023] of AnsiChar; + p_comm :array[0..MAXCOMLEN] of AnsiChar; + prog_name :array[0..1023] of AnsiChar; + p_randomized_path:array[0..7] of AnsiChar; p_klist:t_knlist; @@ -528,6 +529,8 @@ begin mtx_init(p_proc.p_mtx,'process lock'); knlist_init_mtx(@p_proc.p_klist,@p_proc.p_mtx); + + p_proc.p_randomized_path:='system'; end; // diff --git a/sys/kern/subr_dynlib.pas b/sys/kern/subr_dynlib.pas index f33a353f..ff13e3cb 100644 --- a/sys/kern/subr_dynlib.pas +++ b/sys/kern/subr_dynlib.pas @@ -6,159 +6,11 @@ unit subr_dynlib; interface uses + sysutils, mqueue, + elf64, kern_thr, - vfile, - vnode, - vm_object, - vuio, - elf64; - -type - p_image_args=^t_image_args; - t_image_args=packed record - buf :PChar; //pointer to string buffer - begin_argv :PChar; //beginning of argv in buf - begin_envv :PChar; //beginning of envv in buf - endp :PChar; //current `end' pointer of arg & env strings - fname :PChar; //pointer to filename of executable (system space) - fname_buf :PChar; //pointer to optional malloc(M_TEMP) buffer - stringspace:Integer; //space left in arg & env buffer - argc :Integer; //count of argument strings - envc :Integer; //count of environment strings - fd :Integer; //file descriptor of the executable - end; - - p_elf64_auxargs=^t_elf64_auxargs; - t_elf64_auxargs=packed record - execfd:Int64; - phdr :QWORD; - phent :QWORD; - phnum :QWORD; - pagesz:QWORD; - base :QWORD; - flags :QWORD; - entry :QWORD; - end; - - p_authinfo=^t_authinfo; - t_authinfo=packed record - app_type_id:QWORD; - app_flags :QWORD; - app_cap :QWORD; - unknow1 :array[0..1] of QWORD; - s_prog_attr:QWORD; - unknow2 :array[0..10] of QWORD; - end; - {$IF sizeof(t_authinfo)<>136}{$STOP sizeof(t_authinfo)<>136}{$ENDIF} - - p_image_params=^t_image_params; - t_image_params=packed record - vp :p_vnode; - obj :vm_object_t; - attr :p_vattr; - image_self :p_self_header; - image_header:p_elf64_hdr; - entry_addr :Pointer; - reloc_base :Pointer; - opened :Integer; - elf_size :Integer; - auxargs :p_elf64_auxargs; - auxarg_size :QWORD; - args :p_image_args; - execpath :PChar; - execpathp :Pointer; - freepath :PChar; - canary :Pointer; - pagesizes :Pointer; - canarylen :Integer; - pagesizeslen:Integer; - - dyn_vaddr:p_elf64_dyn; - - tls_size :QWORD; - tls_align :QWORD; - tls_init_size:QWORD; - tls_init_addr:Pointer; - - eh_frame_hdr_addr:Pointer; - eh_frame_hdr_size:QWORD; - - authinfo:t_authinfo; - - proc_param_addr:pSceProcParam; - proc_param_size:QWORD; - - module_param_addr:psceModuleParam; - module_param_size:QWORD; - - dyn_id :Integer; - sce_dynlib_data_id:Integer; - sce_comment_id :Integer; - dyn_exist :Integer; - - dyn_offset :QWORD; - dyn_filesz :QWORD; - - sce_dynlib_data_addr:QWORD; - sce_dynlib_data_size:QWORD; - - sce_comment_offset :QWORD; - sce_comment_filesz :QWORD; - - min_addr:QWORD; - max_addr:QWORD; - - relro_addr:Pointer; - relro_size:QWORD; - - hdr_e_type:Integer; - end; - -const - AT_NULL = 0; // Terminates the vector. - AT_IGNORE = 1; // Ignored entry. - AT_EXECFD = 2; // File descriptor of program to load. - AT_PHDR = 3; // Program header of program already loaded. - AT_PHENT = 4; // Size of each program header entry. - AT_PHNUM = 5; // Number of program header entries. - AT_PAGESZ = 6; // Page size in bytes. - AT_BASE = 7; // Interpreter's base address. - AT_FLAGS = 8; // Flags (unused for i386). - AT_ENTRY = 9; // Where interpreter should transfer control. - AT_NOTELF =10; // Program is not ELF ?? - AT_UID =11; // Real uid. - AT_EUID =12; // Effective uid. - AT_GID =13; // Real gid. - AT_EGID =14; // Effective gid. - AT_EXECPATH =15; // Path to the executable. - AT_CANARY =16; // Canary for SSP - AT_CANARYLEN =17; // Length of the canary. - AT_OSRELDATE =18; // OSRELDATE. - AT_NCPUS =19; // Number of CPUs. - AT_PAGESIZES =20; // Pagesizes. - AT_PAGESIZESLEN=21; // Number of pagesizes. - AT_TIMEKEEP =22; // Pointer to timehands. - AT_STACKPROT =23; // Initial stack protection. - - AT_COUNT =24; // Count of defined aux entry types. - - ARG_MAX=262144; // max bytes for an exec function - -type - p_ps_strings=^t_ps_strings; - t_ps_strings=packed record - ps_argvstr :ppchar; //first of 0 or more argument string - ps_nargvstr:Integer; //the number of argument strings - _align1 :Integer; // - ps_envstr :ppchar; //first of 0 or more environment strings - ps_nenvstr :Integer; //the number of environment strings - _align2 :Integer; // - end; - {$IF sizeof(t_ps_strings)<>32}{$STOP sizeof(t_ps_strings)<>32}{$ENDIF} - -const - ps_arg_cache_limit=$400; + kern_rtld; type p_rel_data=^t_rel_data; @@ -339,26 +191,7 @@ type end; -const - M2MB_NOTDYN_FIXED=0; //Default =0 (ATTRIBUTE2:0x00000) - M2MB_DISABLE =1; //NotUsed =32768 (ATTRIBUTE2:0x08000) - M2MB_READONLY =2; //Text_rodata=65536 (ATTRIBUTE2:0x10000) - M2MB_ENABLE =3; //All_section=98304 (ATTRIBUTE2:0x18000) - -const - g_self_fixed:Integer=0; - g_mode_2mb :Integer=M2MB_NOTDYN_FIXED; - budget_ptype_caller:Integer=0; - -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); function scan_phdr(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer; -function is_used_mode_2mb(phdr:p_elf64_phdr;is_dynlib,budget_ptype_caller:Integer):Boolean; function trans_prot(flags:Elf64_Word):Byte; function obj_new():p_lib_info; @@ -366,6 +199,7 @@ procedure obj_free(lib:p_lib_info); function obj_get_str(lib:p_lib_info;offset:Int64):pchar; procedure object_add_name(obj:p_lib_info;name:pchar); +function object_match_name(obj:p_lib_info;name:pchar):Boolean; function Needed_new(lib:p_lib_info;str:pchar):p_Needed_Entry; function Lib_new(d_tag:DWORD;d_val:QWORD):p_Lib_Entry; @@ -393,6 +227,13 @@ procedure initlist_add_neededs(var fini_proc_list:TAILQ_HEAD; function digest_dynamic(lib:p_lib_info):Integer; +procedure dynlibs_add_obj(lib:p_lib_info); + +procedure init_relo_bits_process(lib:p_lib_info); + +function do_load_object(path:pchar):p_lib_info; +function preload_prx_modules(const path:RawByteString):p_lib_info; + var dynlibs_info:t_dynlibs_info; @@ -403,253 +244,7 @@ uses systm, vm, vmparam, - vnode_if; - -function maxInt64(a,b:Int64):Int64; inline; -begin - if (a>b) then Result:=a else Result:=b; -end; - -function minInt64(a,b:Int64):Int64; inline; -begin - if (a0) then - begin - Result:=ENOEXEC; - end; - end; -end; - -procedure exec_load_free(imgp:p_image_params); -begin - FreeMem(imgp^.image_header); - FreeMem(imgp^.image_self); - imgp^.image_header:=nil; - imgp^.image_self:=nil; - imgp^.elf_size:=0; -end; - -function exec_load_self(imgp:p_image_params):Integer; -Var - vp:p_vnode; - obj_size:Int64; - n,s:Int64; - Magic:DWORD; - i,count:Integer; - self_hdr :p_self_header; - self_segs:p_self_segment; - elf_hdr :p_elf64_hdr; - elf_phdr :p_elf64_phdr; - MinSeg :Int64; - MaxSeg :Int64; - src_ofs :Int64; - dst_ofs :Int64; - mem_size :Int64; -begin - Result:=0; - - if (imgp=nil) then Exit(EINVAL); - - vp:=imgp^.vp; - obj_size:=imgp^.attr^.va_size; - - if (obj_size=0) then Exit(ENOEXEC); - - Result:=kread(vp,@Magic,SizeOf(DWORD),0); - if (Result<>0) then Exit; - - case Magic of - ELFMAG: //elf64 - begin - elf_hdr:=AllocMem(obj_size); - - Result:=kread(vp,elf_hdr,obj_size,0); - if (Result<>0) then - begin - FreeMem(elf_hdr); - Exit; - end; - - imgp^.image_header:=elf_hdr; - imgp^.image_self :=nil; - imgp^.elf_size :=obj_size; - end; - SELF_MAGIC: //self - begin - self_hdr:=AllocMem(obj_size); - - Result:=kread(vp,self_hdr,obj_size,0); - if (Result<>0) then - begin - FreeMem(self_hdr); - Exit; - end; - - if (self_hdr^.File_size>obj_size) then - begin - FreeMem(self_hdr); - Exit(EFAULT); - end; - - count:=self_hdr^.Num_Segments; - - if (count=0) then - begin - FreeMem(self_hdr); - Exit(ENOEXEC); - end; - - self_segs:=Pointer(self_hdr+1); - - For i:=0 to count-1 do - if ((self_segs[i].flags and (SELF_PROPS_ENCRYPTED or SELF_PROPS_COMPRESSED))<>0) then - begin - Writeln(StdErr,'exec_load_self:',imgp^.execpath,'is encrypted!'); - FreeMem(self_hdr); - Exit(ENOEXEC); - end; - - elf_hdr:=Pointer(self_segs)+(count*SizeOf(t_self_segment)); - - elf_phdr:=get_elf_phdr(elf_hdr); - - MinSeg:=High(Int64); - MaxSeg:=0; - - count:=self_hdr^.Num_Segments; - - For i:=0 to count-1 do - if ((self_segs[i].flags and SELF_PROPS_BLOCKED)<>0) then - begin - s:=SELF_SEGMENT_INDEX(self_segs[i].flags); - s:=elf_phdr[s].p_offset; - MinSeg:=MinInt64(s,MinSeg); - s:=s+minInt64(self_segs[i].filesz,self_segs[i].filesz); - MaxSeg:=MaxInt64(s,MaxSeg); - end; - - if (MinSeg>MaxSeg) then - begin - FreeMem(self_hdr); - Exit(EFAULT); - end; - - imgp^.image_header:=AllocMem(MaxSeg); - imgp^.elf_size :=MaxSeg; - - //elf_hdr part - n:=ptruint(elf_hdr)-ptruint(self_hdr); //offset to hdr - s:=self_hdr^.Header_Size+self_hdr^.Meta_size; //offset to end - s:=MinInt64(obj_size,s); //min size - s:=MaxInt64(s,n)-n; //get size - - //first page - Move(elf_hdr^,imgp^.image_header^,s); - - count:=self_hdr^.Num_Segments; - - For i:=0 to count-1 do - if ((self_segs[i].flags and SELF_PROPS_BLOCKED)<>0) then - begin - s:=SELF_SEGMENT_INDEX(self_segs[i].flags); - - mem_size:=minInt64(self_segs[i].filesz,self_segs[i].memsz); - - src_ofs:=self_segs[i].offset; //start offset - dst_ofs:=elf_phdr[s].p_offset; //start offset - - fixup_offset_size(src_ofs,mem_size,obj_size); - fixup_offset_size(dst_ofs,mem_size,MaxSeg); - - Move( (Pointer(self_hdr) +src_ofs)^, //src - (Pointer(imgp^.image_header)+dst_ofs)^, //dst - mem_size); //size - end; - - imgp^.image_self:=self_hdr; - end; - else - begin - Exit(ENOEXEC); - end; - end; - -end; - -procedure exec_load_authinfo(imgp:p_image_params); -var - hdr:p_elf64_hdr; - authinfo:p_self_authinfo; - s:ptruint; -begin - if (imgp=nil) then Exit; - - imgp^.authinfo:=Default(t_authinfo); - imgp^.authinfo.app_type_id:=QWORD($3100000000000001); - - if (imgp^.image_header=nil) then Exit; - if (imgp^.image_self =nil) then Exit; - - hdr:=imgp^.image_header; - s:=SizeOf(t_self_header); - s:=s+(imgp^.image_self^.Num_Segments*SizeOf(t_self_segment)); - s:=s+get_elf_phdr_offset(hdr); - s:=s+(hdr^.e_phnum*SizeOf(elf64_phdr)); - s:=AlignUp(s,SELF_SEGMENT_BLOCK_ALIGNMENT); - - authinfo:=Pointer(Pointer(imgp^.image_self)+s); - - imgp^.authinfo.app_type_id:=authinfo^.AuthorityID; -end; + vm_map; function scan_phdr(imgp:p_image_params;phdr:p_elf64_phdr;count:Integer):Integer; var @@ -921,30 +516,6 @@ begin Result:=0; end; -function is_used_mode_2mb(phdr:p_elf64_phdr;is_dynlib,budget_ptype_caller:Integer):Boolean; -var - flag_write:Integer; -begin - Result:=False; - - if (budget_ptype_caller=0) then - begin - flag_write:=2; - if (phdr^.p_type<>PT_SCE_RELRO) then - begin - flag_write:=phdr^.p_flags and 2; - end; - - case g_mode_2mb of - M2MB_NOTDYN_FIXED:Result:=(is_dynlib=0) and (g_self_fixed<>0); - M2MB_READONLY :Result:=(flag_write=0); - M2MB_ENABLE :Result:=True; - else; - end; - - end; -end; - function trans_prot(flags:Elf64_Word):Byte; begin Result:=0; @@ -1545,6 +1116,21 @@ begin TAILQ_INSERT_TAIL(@obj^.names,entry,@entry^.link); end; +function object_match_name(obj:p_lib_info;name:pchar):Boolean; +var + entry:p_Name_Entry; +begin + entry:=TAILQ_FIRST(@obj^.names); + while (entry<>nil) do + begin + if (StrComp(name,@entry^.name)=0) then + begin + Exit(True); + end; + end; + Result:=False; +end; + function Needed_new(lib:p_lib_info;str:pchar):p_Needed_Entry; var len:Integer; @@ -1562,60 +1148,6 @@ begin Result^.export:=ord(d_tag=DT_SCE_IMPORT_LIB); end; -function rtld_dirname(path,bname:pchar):Integer; -var - endp:pchar; -begin - Result:=0; - - { Empty or NULL string gets treated as "." } - if (path=nil) or (path^=#0) then - begin - bname[0]:='.'; - bname[1]:=#0; - Exit(0); - end; - - { Strip trailing slashes } - endp:=path + strlen(path) - 1; - while (endp > path) and ((endp^='/') or (endp^='\')) do Dec(endp); - - { Find the start of the dir } - while (endp > path) and ((endp^<>'/') and (endp^<>'\')) do Dec(endp); - - { Either the dir is "/" or there are no slashes } - if (endp=path) then - begin - if ((endp^='/') or (endp^='\')) then - begin - bname[0]:='/'; - end else - begin - bname[0]:='.'; - end; - bname[1]:=#0; - Exit(0); - end else - begin - repeat - Dec(endp); - until not ((endp > path) and ((endp^='/') or (endp^='\'))); - end; - - if ((endp - path + 2) > PATH_MAX) then - begin - Writeln(StdErr,'Filename is too long:',path); - Exit(-1); - end; - - Move(path^, bname^, endp - path + 1); - bname[endp - path + 1]:=#0; - - Result:=0; -end; - - - procedure initlist_add_objects(var fini_proc_list:TAILQ_HEAD; obj :p_lib_info; tail:p_lib_info; @@ -1974,6 +1506,183 @@ begin end; +procedure dynlibs_add_obj(lib:p_lib_info); +begin + TAILQ_INSERT_TAIL(@dynlibs_info.lib_list,lib,@lib^.entry); + Inc(dynlibs_info.obj_count); +end; + +procedure init_relo_bits_process(lib:p_lib_info); +var + count:Integer; +begin + if (lib^.rel_data=nil) then + begin + count:=0; + end else + begin + count:=(lib^.rel_data^.pltrela_size div sizeof(elf64_rela))+(lib^.rel_data^.rela_size div sizeof(elf64_rela)); + end; + + lib^.relo_bits_process:=AllocMem((count+7) div 8); +end; + +function self_load_shared_object(path:pchar;new:p_lib_info):Integer; +begin + Result:=-1; + + ////////// +end; + +function do_load_object(path:pchar):p_lib_info; +label + _inc_max, + _error; +var + fname:RawByteString; + new:p_lib_info; + lib:p_lib_info; + i,err:Integer; + tls_max:Integer; + map_base:Pointer; + map_size:QWORD; + map:vm_map_t; +begin + Result:=nil; + + new:=obj_new(); + + err:=self_load_shared_object(path,new); + if (err<>0) then + begin + goto _error; + end; + + fname:=ExtractFileName(path); + object_add_name(new,pchar(fname)); + + _set_lib_path(new,path); + + if (new^.tls_size=0) then + begin + i:=0; + end else + begin + dynlibs_info.tls_count:=dynlibs_info.tls_count + 1; + tls_max:=dynlibs_info.tls_max; + + if (tls_max<1) then + begin + _inc_max: + i:=tls_max+1; + dynlibs_info.tls_max:=i; + end else + begin + i:=1; + lib:=TAILQ_FIRST(@dynlibs_info.lib_list); + while (lib<>nil) do + begin + while (lib^.tls_index=i) do + begin + i:=i+1; + lib:=TAILQ_FIRST(@dynlibs_info.lib_list); + if (tls_max < i) then + begin + goto _inc_max; + end; + end; + lib:=TAILQ_NEXT(lib,@lib^.entry); + end; + end; + end; + + new^.tls_index:=i; + + err:=digest_dynamic(new); + if (err<>0) then + begin + Writeln(StdErr,'do_load_object:','digest_dynamic() failed rv=',err); + goto _error; + end; + + //err:=dynlib_initialize_pltgot_each(new); + if (err<>0) then + begin + Writeln(StdErr,'do_load_object:','dynlib_initialize_pltgot_each() failed rv=',err); + goto _error; + end; + + if (new^.textrel<>0) then + begin + Writeln(StdErr,'do_load_object:',new^.lib_path,' has impure text'); + err:=EINVAL; + goto _error; + end; + + init_relo_bits_process(lib); + dynlibs_add_obj(new); + new^.loaded:=1; + Exit(new); + + _error: + + map_base:=new^.map_base; + map_size:=new^.map_size; + + if (map_base<>nil) then + begin + map:=@g_vmspace.vm_map; + + vm_map_lock(map); + vm_map_delete(map,QWORD(map_base),QWORD(map_base) + map_size); + vm_map_unlock(map); + end; + + obj_free(new); + + Exit(nil); +end; + +function preload_prx_modules(const path:RawByteString):p_lib_info; +label + _do_load; +var + lib:p_lib_info; + fname:RawByteString; +begin + Result:=nil; + + fname:=ExtractFileName(path); + + lib:=TAILQ_FIRST(@dynlibs_info.lib_list); + while (lib<>nil) do + begin + if object_match_name(lib,pchar(fname)) then + begin + Exit(lib); + end; + lib:=TAILQ_NEXT(lib,@lib^.entry); + 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; + + 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: + + Result:=do_load_object(pchar(fname)); +end; end. diff --git a/sys/test/project1.lpi b/sys/test/project1.lpi index 35d00ae4..49e1a312 100644 --- a/sys/test/project1.lpi +++ b/sys/test/project1.lpi @@ -573,6 +573,10 @@ + + + + diff --git a/sys/vfs/vfs_lookup.pas b/sys/vfs/vfs_lookup.pas index 271d743a..891a968e 100644 --- a/sys/vfs/vfs_lookup.pas +++ b/sys/vfs/vfs_lookup.pas @@ -1095,10 +1095,14 @@ begin FreeMem(ndp^.ni_cnd.cn_pnbuf); ndp^.ni_cnd.cn_flags:=ndp^.ni_cnd.cn_flags and (not HASBUF); end; + if ((flags and NDF_NO_VP_UNLOCK)=0) and ((ndp^.ni_cnd.cn_flags and LOCKLEAF)<>0) and (ndp^.ni_vp<>nil) then + begin unlock_vp:=1; + end; + if (((flags and NDF_NO_VP_RELE)=0) and (ndp^.ni_vp<>nil)) then begin if (unlock_vp<>0) then @@ -1106,15 +1110,24 @@ begin vput(ndp^.ni_vp); unlock_vp:=0; end else + begin vrele(ndp^.ni_vp); + end; ndp^.ni_vp:=nil; end; + if (unlock_vp<>0) then + begin VOP_UNLOCK(ndp^.ni_vp, 0); + end; + if ((flags and NDF_NO_DVP_UNLOCK)=0) and ((ndp^.ni_cnd.cn_flags and LOCKPARENT)<>0) and (ndp^.ni_dvp<>ndp^.ni_vp) then + begin unlock_dvp:=1; + end; + if ((flags and NDF_NO_DVP_RELE)=0) and ((ndp^.ni_cnd.cn_flags and (LOCKPARENT or WANTPARENT))<>0) then begin @@ -1123,11 +1136,17 @@ begin vput(ndp^.ni_dvp); unlock_dvp:=0; end else + begin vrele(ndp^.ni_dvp); + end; ndp^.ni_dvp:=nil; end; + if (unlock_dvp<>0) then + begin VOP_UNLOCK(ndp^.ni_dvp, 0); + end; + if ((flags and NDF_NO_STARTDIR_RELE)=0) and ((ndp^.ni_cnd.cn_flags and SAVESTART)<>0) then begin diff --git a/sys/vfs/vfs_mountroot.pas b/sys/vfs/vfs_mountroot.pas index 01cbb140..71993dc7 100644 --- a/sys/vfs/vfs_mountroot.pas +++ b/sys/vfs/vfs_mountroot.pas @@ -386,6 +386,12 @@ begin error:=vfs_mountroot_simple('ufs','/app0','/',nil,0); end; + error:=kern_mkdir('system',UIO_SYSSPACE,&777); + if (error=0) then + begin + error:=vfs_mountroot_simple('ufs','/system','/system',nil,0); + end; + //error:=kern_unmount('/app0',0); mount_print;