From 8740fedec56b1e418ad7c9204ff1b81143c5f3c4 Mon Sep 17 00:00:00 2001 From: Pavel <68122101+red-prig@users.noreply.github.com> Date: Tue, 18 Jul 2023 22:09:36 +0300 Subject: [PATCH] + --- sys/elf64.pas | 2 +- sys/kern/kern_exec.pas | 19 +-- sys/kern/kern_reloc.pas | 324 ++++++++++++++++++++++++++++++++++++++- sys/kern/kern_rtld.pas | 29 +++- sys/kern/subr_dynlib.pas | 147 +++++++++++++++--- 5 files changed, 483 insertions(+), 38 deletions(-) diff --git a/sys/elf64.pas b/sys/elf64.pas index 43688742..69c753e3 100644 --- a/sys/elf64.pas +++ b/sys/elf64.pas @@ -636,7 +636,7 @@ function SELF_WINDOW(i:Int64):Integer; inline; function SELF_BLOCK_SIZE(i:Int64):Int64; inline; function SELF_SEGMENT_INDEX(i:Int64):Integer; inline; -function ELF64_R_SYM(i:QWORD):DWORD; inline; +function ELF64_R_SYM (i:QWORD):DWORD; inline; function ELF64_R_TYPE(i:QWORD):DWORD; inline; function ELF64_ST_BIND(i:Byte):Byte; inline; function ELF64_ST_TYPE(i:Byte):Byte; inline; diff --git a/sys/kern/kern_exec.pas b/sys/kern/kern_exec.pas index 317cf856..7a6b88f7 100644 --- a/sys/kern/kern_exec.pas +++ b/sys/kern/kern_exec.pas @@ -760,15 +760,16 @@ begin TAILQ_INIT(@dynlibs_info.fini_list); TAILQ_INIT(@dynlibs_info.obj_list); - dynlibs_info.obj_count :=0; - dynlibs_info.tls_last_offset:=0; - dynlibs_info.tls_last_size :=0; - dynlibs_info.d_tls_count :=0; - dynlibs_info.tls_count :=1; - dynlibs_info.tls_max :=1; - //dynlibs_info.bits :=0; + dynlibs_info.obj_count :=0; + dynlibs_info.tls_last_offset :=0; + dynlibs_info.tls_last_size :=0; + dynlibs_info.tls_static_space:=0; + dynlibs_info.tls_count :=1; + dynlibs_info.tls_max :=1; + //dynlibs_info.bits :=0; lib:=obj_new(); + lib^.mainprog:=1; lib^.relocbase:=imgp^.reloc_base; text_addr:=g_vmspace.vm_taddr; @@ -864,7 +865,7 @@ begin Exit; end; - init_relo_bits_process(lib); + init_relo_bits(lib); dynlibs_add_obj(lib); @@ -1026,7 +1027,7 @@ begin ET_SCE_DYNEXEC : else begin - Writeln(StdErr,'exec_self_imgact:',imgp^.execpath,' unspported e_type:',HexStr(hdr^.e_type,4)); + Writeln(StdErr,'exec_self_imgact:',imgp^.execpath,' unspported e_type:0x',HexStr(hdr^.e_type,4)); Exit(ENOEXEC); end; end; diff --git a/sys/kern/kern_reloc.pas b/sys/kern/kern_reloc.pas index 6acc1a80..3cff529d 100644 --- a/sys/kern/kern_reloc.pas +++ b/sys/kern/kern_reloc.pas @@ -6,6 +6,7 @@ unit kern_reloc; interface uses + sysutils, mqueue, elf64, kern_thr, @@ -16,12 +17,333 @@ function relocate_one_object(obj:p_lib_info;jmpslots:Integer):Integer; implementation +uses + errno, + systm, + kern_dlsym; + +function check_addr(obj:p_lib_info;where:Pointer;size:Integer):Integer; +var + map_base:Pointer; + relro_addr:Pointer; +begin + map_base:=obj^.map_base; + relro_addr:=obj^.relro_addr; + + if ( (map_base > where) or + ((map_base + obj^.text_size) < (where + size)) + ) and + + ( (obj^.data_addr > where) or + ((obj^.data_addr + obj^.data_size) < (where + size)) + + ) and + ( (relro_addr=nil) or + (relro_addr > where) or + (obj^.relro_size=0) or + ((relro_addr + obj^.relro_size) < (where + size)) + ) then + begin + Exit(ENOEXEC); + end; + + Result:=0; +end; + function reloc_non_plt(obj:p_lib_info):Integer; +label + _next, + _move64; +var + rela:p_elf64_rela; + sym_zero:p_elf64_sym; + + where:Pointer; + data:Pointer; + + data32:Integer; + r_type:Integer; + + def:p_elf64_sym; + defobj:p_lib_info; + + cache:array of t_SymCache; + + i,count:Integer; begin Result:=0; - ////// + + cache:=nil; + SetLength(cache,obj^.rel_data^.dynsymcount); + + sym_zero:=@dynlibs_info.sym_zero; + + rela :=obj^.rel_data^.rela_addr; + count:=obj^.rel_data^.rela_size div SizeOf(elf64_rela); + + defobj:=nil; + + if (rela<>nil) and (count<>0) then + For i:=0 to count-1 do + if not check_relo_bits(obj,i) then + begin + where:=Pointer(obj^.relocbase)+rela^.r_offset; + + r_type:=ELF64_R_TYPE(rela^.r_info); + + case r_type of + + R_X86_64_NONE:; //ignore + + R_X86_64_COPY: + if (obj^.mainprog=0) then + begin + Writeln(StdErr,'reloc_non_plt:','Unexpected R_X86_64_COPY relocation in shared library'); + Exit(ENOEXEC); + end; //R_X86_64_COPY + + R_X86_64_RELATIVE: + begin + Result:=check_addr(obj,where,SizeOf(Pointer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','idx=',i,' where=0x',HexStr(where),' ref=',dynlib_basename(obj^.lib_path)); + Exit; + end; + + data:=(obj^.relocbase + rela^.r_addend); + + defobj:=obj; + goto _move64; + end; //R_X86_64_RELATIVE + + R_X86_64_64, + R_X86_64_GLOB_DAT, + R_X86_64_DTPMOD64, + R_X86_64_DTPOFF64, + R_X86_64_TPOFF64: //64 + begin + Result:=check_addr(obj,where,SizeOf(Pointer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','idx=',i,' where=0x',HexStr(where),' ref=',dynlib_basename(obj^.lib_path)); + Exit; + end; + + def:=find_symdef(ELF64_R_SYM(rela^.r_info),obj,defobj,0,@cache[0]); + + if (def<>nil) then + case r_type of + R_X86_64_64: + begin + data:=(defobj^.relocbase + rela^.r_addend + def^.st_value); + + if (def<>sym_zero) then + begin + goto _move64; + end; + end; //R_X86_64_64 + + R_X86_64_GLOB_DAT: + begin + data:=(defobj^.relocbase + def^.st_value); + + if (def<>sym_zero) then + begin + goto _move64; + end; + end; //R_X86_64_GLOB_DAT + + R_X86_64_DTPMOD64: + begin + Result:=copyin(where,@data,SizeOf(Pointer)); //data:=where^ + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + data:=(data + defobj^.tls_index); + + Result:=copyout(@data,where,8); //where^:=data + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + set_relo_bits(obj,i); + end; //R_X86_64_DTPMOD64 + + R_X86_64_DTPOFF64: + begin + Result:=copyin(where,@data,SizeOf(Pointer)); //data:=where^ + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + data:=(data + rela^.r_addend + def^.st_value); + + Result:=copyout(@data,where,8); //where^:=data + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + set_relo_bits(obj,i); + end; //R_X86_64_DTPOFF64 + + R_X86_64_TPOFF64: + begin + if not allocate_tls_offset(defobj) then + begin + Writeln(StdErr,'reloc_non_plt:','No space available for static Thread Local Storage'); + Exit(ENOEXEC); + end; + + data:=Pointer(def^.st_value - defobj^.tls_offset + rela^.r_addend); + + Result:=copyout(@data,where,SizeOf(Pointer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + set_relo_bits(obj,i); + end; //R_X86_64_TPOFF64 + + else; + end; //case + + end; //R_X86_64_*64 + + R_X86_64_PC32, + R_X86_64_DTPOFF32, + R_X86_64_TPOFF32: //32 + begin + Result:=check_addr(obj,where,SizeOf(Integer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','idx=',i,' where=0x',HexStr(where),' ref=',dynlib_basename(obj^.lib_path)); + Exit; + end; + + def:=find_symdef(ELF64_R_SYM(rela^.r_info),obj,defobj,0,@cache[0]); + + if (def<>nil) then + case r_type of + + R_X86_64_PC32: + begin + data32:=(Integer(QWORD(defobj^.relocbase)) - Integer(QWORD(where))) + Integer(def^.st_value) + Integer(rela^.r_addend); + + if (def<>sym_zero) then + begin + data:=Pointer(QWORD(data32)); + Result:=check_addr(defobj,data,SizeOf(Integer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','idx=',i,' where32=0x',HexStr(data32,8),' ref=',dynlib_basename(defobj^.lib_path)); + Exit; + end; + end; + + Result:=relocate_text_or_data_segment(obj,@data32,where,SizeOf(Integer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where32=0x',HexStr(data32,8),' [',r_type,']'); + Exit(ENOEXEC); + end; + + set_relo_bits(obj,i); + end; //R_X86_64_PC32 + + R_X86_64_DTPOFF32: + begin + Result:=copyin(where,@data,SizeOf(Pointer)); //data:=where^ + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyin() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + data:=(data + rela^.r_addend + def^.st_value); + + Result:=copyout(@data,where,8); //where^:=data + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + set_relo_bits(obj,i); + end; //R_X86_64_DTPOFF32 + + + R_X86_64_TPOFF32: + begin + if not allocate_tls_offset(defobj) then + begin + Writeln(StdErr,'reloc_non_plt:','No space available for static Thread Local Storage'); + Exit(ENOEXEC); + end; + + data32:=Integer(def^.st_value) - Integer(defobj^.tls_offset) + Integer(rela^.r_addend); + + Result:=copyout(@data32,where,SizeOf(Integer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + set_relo_bits(obj,i); + end; //R_X86_64_TPOFF32 + + else; + end; //case + + end; //R_X86_64_*32 + + else + begin + Writeln(StdErr,'reloc_non_plt:','Unsupported reloc type=',r_type); + Exit(ENOEXEC); + end; + end; //case + + // + _next: + Inc(rela); + end; + + Exit(0); + _move64: + + Result:=check_addr(defobj,data,SizeOf(Pointer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','idx=',i,' where=0x',HexStr(data),' ref=',dynlib_basename(defobj^.lib_path)); + Exit; + end; + + Result:=relocate_text_or_data_segment(obj,@data,where,SizeOf(Pointer)); + if (Result<>0) then + begin + Writeln(StdErr,'reloc_non_plt:','copyout() failed. where=0x',HexStr(data),' [',r_type,']'); + Exit(ENOEXEC); + end; + + set_relo_bits(obj,i); + + goto _next; end; + function reloc_jmplots(obj:p_lib_info):Integer; begin Result:=0; diff --git a/sys/kern/kern_rtld.pas b/sys/kern/kern_rtld.pas index 206fe7be..87e87ac4 100644 --- a/sys/kern/kern_rtld.pas +++ b/sys/kern/kern_rtld.pas @@ -208,6 +208,7 @@ function self_load_section(imgp:p_image_params; function is_system_path(path:pchar):Boolean; function is_libc_or_fios(path:pchar):Boolean; +function dynlib_basename(path:pchar):pchar; implementation @@ -472,10 +473,18 @@ 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; + if (imgp^.image_header=nil) or + (imgp^.image_self =nil) then + begin + case ExtractFileExt(imgp^.execpath) of + '.sprx','.prx' :imgp^.authinfo.app_type_id:=QWORD($3900000000000002); + '.sdll','.sexe':imgp^.authinfo.app_type_id:=QWORD($3901000000000001); + else + imgp^.authinfo.app_type_id:=QWORD($3100000000000001); + end; + Exit; + end; hdr:=imgp^.image_header; s:=SizeOf(t_self_header); @@ -1181,5 +1190,19 @@ begin end; end; +function dynlib_basename(path:pchar):pchar; +var + idx:pchar; +begin + idx:=strrscan(path,'/'); + if (idx=nil) then + begin + Result:=path; + end else + begin + Result:=idx+1; + end; +end; + end. diff --git a/sys/kern/subr_dynlib.pas b/sys/kern/subr_dynlib.pas index 97676b5c..afb77d85 100644 --- a/sys/kern/subr_dynlib.pas +++ b/sys/kern/subr_dynlib.pas @@ -113,10 +113,11 @@ type //t_rtld_bits rtld_flags; + mainprog :Integer; tls_done :Integer; init_scanned :Integer; init_done :Integer; - init_fini :Integer; + on_fini_list :Integer; textrel :Integer; init_plt :Integer; is_system :Integer; @@ -126,7 +127,7 @@ type dldags :TAILQ_HEAD; //Objlist_Entry dagmembers:TAILQ_HEAD; //Objlist_Entry - relo_bits_process:PByte; + relo_bits:PByte; rel_data:p_rel_data; @@ -188,9 +189,9 @@ type init_proc_list:TAILQ_HEAD; //p_Objlist_Entry fini_proc_list:TAILQ_HEAD; //p_Objlist_Entry - tls_last_offset:QWORD; - tls_last_size :QWORD; - d_tls_count :QWORD; + tls_last_offset :QWORD; + tls_last_size :QWORD; + tls_static_space:QWORD; tls_count :Integer; tls_max :Integer; @@ -228,6 +229,9 @@ procedure _set_lib_path(lib:p_lib_info;path:PAnsiChar); procedure release_per_file_info_obj(lib:p_lib_info); function acquire_per_file_info_obj(imgp:p_image_params;new:p_lib_info):Integer; +function allocate_tls_offset(obj:p_lib_info):Boolean; +procedure free_tls_offset(obj:p_lib_info); + procedure initlist_add_objects(var fini_proc_list:TAILQ_HEAD; obj :p_lib_info; tail:p_lib_info; @@ -241,7 +245,9 @@ 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); +procedure init_relo_bits (obj:p_lib_info); +function check_relo_bits(obj:p_lib_info;i:Integer):Boolean; +procedure set_relo_bits(obj:p_lib_info;i:Integer); procedure donelist_init(var dlp:t_DoneList); inline; function donelist_check(var dlp:t_DoneList;obj:p_lib_info):Boolean; inline; @@ -249,6 +255,8 @@ function donelist_check(var dlp:t_DoneList;obj:p_lib_info):Boolean; inline; function change_relro_protection(obj:p_lib_info;prot:Integer):Integer; function change_relro_protection_all(prot:Integer):Integer; +function relocate_text_or_data_segment(obj:p_lib_info;src,dst:Pointer;size:QWORD):Integer; + procedure init_dag (root:p_lib_info); procedure ref_dag (root:p_lib_info); procedure unref_dag(root:p_lib_info); @@ -548,7 +556,7 @@ begin $6100003e: begin _unsupp: - Writeln(StdErr,'preprocess_dt_entries:','Unsupported DT tag ',HexStr(dt_ent^.d_tag,8),' found in ',new^.lib_path); + Writeln(StdErr,'preprocess_dt_entries:','Unsupported DT tag 0x',HexStr(dt_ent^.d_tag,8),' found in ',new^.lib_path); Exit(ENOEXEC); end; @@ -558,7 +566,7 @@ begin DT_RELA, DT_JMPREL: begin - Writeln(StdErr,'preprocess_dt_entries:','ORBIS object file does not support DT tag ',HexStr(dt_ent^.d_tag,8),' found in ',new^.lib_path); + Writeln(StdErr,'preprocess_dt_entries:','ORBIS object file does not support DT tag 0x',HexStr(dt_ent^.d_tag,8),' found in ',new^.lib_path); Exit(EINVAL); end; @@ -684,11 +692,50 @@ begin end; -procedure free_tls_offset(lib:p_lib_info); +function allocate_tls_offset(obj:p_lib_info):Boolean; +var + off:Int64; begin - if (lib^.tls_done<>0) and (lib^.tls_offset=dynlibs_info.tls_last_offset) then + if (obj^.tls_done<>0) then begin - dynlibs_info.tls_last_offset:=lib^.tls_offset - lib^.tls_size; + Exit(True); + end; + + off:=obj^.tls_size; + if (off=0) then + begin + obj^.tls_done:=1; + Exit(True); + end; + + if (obj^.tls_index=1) then + begin + off:=off + -1; + end else + begin + off:=off + -1 + dynlibs_info.tls_last_offset; + end; + + off:=(off + obj^.tls_align) and (-obj^.tls_align); + + if ((dynlibs_info.tls_static_space<>0) and (dynlibs_info.tls_static_space < off)) then + begin + Exit(False); + end; + + obj^.tls_offset:=off; + + dynlibs_info.tls_last_offset:=off; + dynlibs_info.tls_last_size :=obj^.tls_size; + + Result:=True; +end; + +procedure free_tls_offset(obj:p_lib_info); +begin + if (obj^.tls_done<>0) and (obj^.tls_offset=dynlibs_info.tls_last_offset) then + begin + dynlibs_info.tls_last_offset:=obj^.tls_offset - obj^.tls_size; dynlibs_info.tls_last_size :=0; end; end; @@ -747,10 +794,10 @@ begin lib^.lib_path:=nil; end; - if (lib^.relo_bits_process<>nil) then + if (lib^.relo_bits<>nil) then begin - FreeMem(lib^.relo_bits_process); - lib^.relo_bits_process:=nil + FreeMem(lib^.relo_bits); + lib^.relo_bits:=nil end; libs:=TAILQ_FIRST(@lib^.lib_table); @@ -806,7 +853,7 @@ function obj_get_str(lib:p_lib_info;offset:Int64):pchar; begin if (lib^.rel_data^.strtab_size<=offset) then begin - Writeln(StdErr,'obj_get_str:','offset=',HexStr(offset,8),' is out of range of string table of ',lib^.lib_path); + Writeln(StdErr,'obj_get_str:','offset=0x',HexStr(offset,8),' is out of range of string table of ',lib^.lib_path); Exit(nil); end; @@ -881,11 +928,11 @@ begin objlist_push_tail(init_proc_list,obj); end; - if (obj^.fini_proc_addr<>nil) and (obj^.init_fini=0) then + if (obj^.fini_proc_addr<>nil) and (obj^.on_fini_list=0) then begin objlist_push_tail(fini_proc_list,obj); - obj^.init_fini:=1; + obj^.on_fini_list:=1; end; end; @@ -1153,7 +1200,7 @@ begin else begin - Writeln(StdErr,'digest_dynamic:','Unsupported DT tag ',HexStr(dt_ent^.d_tag,8),' found in ',lib^.lib_path); + Writeln(StdErr,'digest_dynamic:','Unsupported DT tag 0x',HexStr(dt_ent^.d_tag,8),' found in ',lib^.lib_path); Exit(ENOEXEC); end; @@ -1212,19 +1259,40 @@ begin Inc(dynlibs_info.obj_count); end; -procedure init_relo_bits_process(lib:p_lib_info); +procedure init_relo_bits(obj:p_lib_info); var count:Integer; begin - if (lib^.rel_data=nil) then + if (obj^.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)); + count:=(obj^.rel_data^.pltrela_size div sizeof(elf64_rela))+(obj^.rel_data^.rela_size div sizeof(elf64_rela)); end; - lib^.relo_bits_process:=AllocMem((count+7) div 8); + if (count=0) then + begin + obj^.relo_bits:=nil; + end else + begin + obj^.relo_bits:=AllocMem((count+7) div 8); + end; + +end; + +function check_relo_bits(obj:p_lib_info;i:Integer):Boolean; +begin + if (obj^.relo_bits=nil) then Exit(False); + + Result:=((obj^.relo_bits[i shr 3] shr (i and 7)) and 1)<>0; +end; + +procedure set_relo_bits(obj:p_lib_info;i:Integer); +begin + if (obj^.relo_bits=nil) then Exit; + + obj^.relo_bits[i shr 3]:=obj^.relo_bits[i shr 3] or (1 shl (i and 7)) end; function dynlib_load_sections(imgp:p_image_params;new:p_lib_info;phdr:p_elf64_phdr;count:Integer;delta:QWORD):Integer; @@ -1513,7 +1581,7 @@ begin ET_SCE_DYNAMIC: else begin - Writeln(StdErr,'self_load_shared_object:',imgp^.execpath,' Unsupported ELF e_type:',HexStr(hdr^.e_type,4)); + Writeln(StdErr,'self_load_shared_object:',imgp^.execpath,' Unsupported ELF e_type:0x',HexStr(hdr^.e_type,4)); error:=ENOEXEC; goto _fail_dealloc; end; @@ -1645,6 +1713,37 @@ begin end; end; +function relocate_text_or_data_segment(obj:p_lib_info;src,dst:Pointer;size:QWORD):Integer; +var + map:vm_map_t; +begin + if (obj^.textrel=0) or + (obj^.map_base > dst) or + ((obj^.map_base + obj^.text_size) < (dst + size)) then + begin + Result:=copyout(src,dst,size); + end else + if (p_proc.p_sdk_version < $1700000) then + begin + map:=@g_vmspace.vm_map; + // + vm_map_lock(map); + // + Result:=change_relro_protection(obj,VM_PROT_RW); + if (Result<>0) then Exit; + + Result:=copyout(src,dst,size); + + change_relro_protection(obj,VM_PROT_READ); + // + vm_map_unlock(map); + end else + begin + Writeln(StdErr,'relocate_text_or_data_segment:','text relocation is prohibited.'); + Exit(ENOEXEC); + end; +end; + procedure donelist_init(var dlp:t_DoneList); inline; begin SetLength(dlp.objs,dynlibs_info.obj_count); @@ -1892,7 +1991,7 @@ begin goto _error; end; - init_relo_bits_process(lib); + init_relo_bits(lib); dynlibs_add_obj(new); new^.loaded:=1; Exit(new);