This commit is contained in:
Pavel 2023-07-18 22:09:36 +03:00
parent 55b69eaa8e
commit 8740fedec5
5 changed files with 483 additions and 38 deletions

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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.

View File

@ -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);