This commit is contained in:
Pavel 2023-07-26 14:47:39 +03:00
parent 5cf6bf9908
commit 798b0b2cce
12 changed files with 568 additions and 40 deletions

View File

@ -22,6 +22,7 @@ type
procedure add_patch_link (_obj,vaddr:Pointer;ptype:t_patch_type;stub:p_stub_chunk);
procedure free_patch_link(_obj:Pointer;node:p_patch_node);
procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
procedure patcher_process_section(_obj,data,vaddr:Pointer;filesz:QWORD);
@ -32,6 +33,7 @@ uses
kern_rwlock,
kern_thr,
vm,
vmparam,
vm_map,
vm_mmap,
vm_object,
@ -67,6 +69,33 @@ begin
FreeMem(node);
end;
function OFF_TO_IDX(x:Pointer):DWORD; inline;
begin
Result:=QWORD(x) shr PAGE_SHIFT;
end;
procedure vm_object_patch_remove(_obj:Pointer;start,__end:DWORD);
var
obj:vm_object_t;
entry,next:p_patch_node;
begin
obj:=_obj;
entry:=TAILQ_FIRST(@obj^.patchq);
while (entry<>nil) do
begin
next:=TAILQ_NEXT(entry,@entry^.link);
//
if ((start=0) or (OFF_TO_IDX(entry^.vaddr)>=start)) and
((__end=0) or (OFF_TO_IDX(entry^.vaddr)<=__end)) then
begin
free_patch_link(_obj,entry);
end;
//
entry:=next;
end;
end;
{
64 48 A1 [0000000000000000] mov rax,fs:[$0000000000000000] -> 65 48 A1 [0807000000000000] mov rax,gs:[$0000000000000708]
64 48 8B 04 25 [00000000] mov rax,fs:[$00000000] -> 65 48 8B 04 25 [08070000] mov rax,gs:[$00000708]

View File

@ -443,6 +443,8 @@ end;
function relocate_one_object(obj:p_lib_info;jmpslots:Integer):Integer;
begin
Writeln(' relocate:',dynlib_basename(obj^.lib_path));
Result:=reloc_non_plt(obj);
if (Result<>0) then
begin

View File

@ -524,6 +524,19 @@ begin
end;
end;
function get_char_sep(path:pchar):char; inline;
const
c_host='/host/';
begin
if (StrLComp(path,c_host,Length(c_host))=0) then
begin
Result:='\';
end else
begin
Result:='/';
end;
end;
function rtld_dirname(path,bname:pchar):Integer;
var
endp:pchar;
@ -539,13 +552,7 @@ begin
Exit(0);
end;
if (StrLComp(path,'/host/',Length('/host/'))=0) then
begin
chr:='/';
end else
begin
chr:='\';
end;
chr:=get_char_sep(path);
{ Strip trailing slashes }
endp:=path + strlen(path) - 1;
@ -1140,26 +1147,10 @@ begin
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;
if (path=nil) then Exit(False);
if (path[0]<>'/') then Exit(False);
Result:=StrLComp(p_proc.p_randomized_path,@path[1],Length(p_proc.p_randomized_path))=0;
end;
function dynlib_basename(path:pchar):pchar;
@ -1167,13 +1158,7 @@ var
idx:pchar;
chr:char;
begin
if (StrLComp(path,'/host/',Length('/host/'))=0) then
begin
chr:='/';
end else
begin
chr:='\';
end;
chr:=get_char_sep(path);
idx:=strrscan(path,chr);
if (idx=nil) then
@ -1185,5 +1170,25 @@ begin
end;
end;
function is_libc_or_fios(path:pchar):Boolean;
const
c_libc='libc.';
c_libSceFios2='libSceFios2.';
var
f:pchar;
begin
f:=dynlib_basename(path);
if (StrLComp(f,c_libc,Length(c_libc))=0) or
(StrLComp(f,c_libSceFios2,Length(c_libSceFios2))=0) then
begin
Result:=True;
end else
begin
Result:=False;
end;
end;
end.

440
sys/kern/kern_sysctl.pas Normal file
View File

@ -0,0 +1,440 @@
unit kern_sysctl;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
const
CTL_MAXNAME=24; // largest number of components supported
//Top-level identifiers
CTL_UNSPEC = 0; // unused
CTL_KERN = 1; // "high kernel": proc, limits
CTL_VM = 2; // virtual memory
CTL_VFS = 3; // filesystem, mount type is next
CTL_NET = 4; // network, see socket.h
CTL_DEBUG = 5; // debugging parameters
CTL_HW = 6; // generic cpu/io
CTL_MACHDEP = 7; // machine dependent
CTL_USER = 8; // user-level
CTL_P1003_1B= 9; // POSIX 1003.1B
CTL_MAXID =10; // number of valid top-level ids
//CTL_KERN identifiers
KERN_PROC =14;
KERN_ARND =37;
//KERN_PROC subtypes
KERN_PROC_APPINFO =35; //Application information
KERN_PROC_SDK_VERSION =36; //SDK version of the executable file
KERN_PROC_IDTABLE =37; //ID table information
KERN_PROC_TEXT_SEGMENT=44; //kern_dynlib_get_libkernel_text_segment
//SYSCTL_HANDLER_ARGS oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req
type
p_sysctl_req=^t_sysctl_req;
t_sysctl_func=function(req:p_sysctl_req;p:Pointer;s:QWORD):Integer;
t_sysctl_req=record
td :Pointer; //p_kthread
lock :Integer;
oldptr :Pointer;
oldlen :QWORD;
oldidx :QWORD;
oldfunc :t_sysctl_func;
newptr :Pointer;
newlen :QWORD;
newidx :QWORD;
newfunc :t_sysctl_func;
validlen:QWORD;
flags :Integer;
end;
p_sysctl_oid=^t_sysctl_oid;
t_oid_handler=function(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
t_sysctl_oid=record
oid_handler:t_oid_handler;
end;
function sys___sysctl(name :PInteger;
namelen:DWORD;
old :Pointer;
oldlenp:PQWORD;
new :Pointer;
newlen :QWORD):Integer;
procedure sysctl_register_all(); //SYSINIT(sysctl, SI_SUB_KMEM, SI_ORDER_ANY, sysctl_register_all, 0);
implementation
uses
errno,
systm,
vmparam,
kern_thr,
kern_sx,
md_arc4random;
var
sysctllock :t_sx;
sysctlmemlock:t_sx;
procedure sysctl_register_all();
begin
sx_init(@sysctlmemlock, 'sysctl mem');
sx_init(@sysctllock , 'sysctl lock');
end;
procedure SYSCTL_XLOCK(); inline;
begin
sx_xlock(@sysctllock)
end;
procedure SYSCTL_XUNLOCK(); inline;
begin
sx_xunlock(@sysctllock);
end;
procedure SYSCTL_ASSERT_XLOCKED(); inline;
begin
sx_assert(@sysctllock)
end;
function SYSCTL_IN(req:p_sysctl_req;p:Pointer;s:QWORD):Integer; inline;
begin
Result:=req^.newfunc(req,p,s);
end;
function SYSCTL_OUT(req:p_sysctl_req;p:Pointer;s:QWORD):Integer; inline;
begin
Result:=req^.oldfunc(req,p,s);
end;
function SYSCTL_HANDLE(noid:p_sysctl_oid;func:Pointer):Integer; inline;
begin
noid^.oid_handler:=t_oid_handler(func);
Result:=0
end;
//Transfer function to/from user space.
function sysctl_old_user(req:p_sysctl_req;p:Pointer;l:QWORD):Integer;
var
i,len,origidx:QWORD;
error:Integer;
begin
origidx:=req^.oldidx;
Inc(req^.oldidx,l);
if (req^.oldptr=nil) then
begin
Exit(0);
end;
i:=l;
len:=req^.validlen;
if (len <= origidx) then
begin
i:=0;
end else
begin
if (i > len - origidx) then
begin
i:=len - origidx;
end;
//if (req^.lock=REQ_WIRED) then
//begin
// error:=copyout_nofault(p, req^.oldptr + origidx, i);
//end else
begin
error:=copyout(p, req^.oldptr + origidx, i);
end;
if (error<>0) then
begin
Exit(error);
end;
end;
if (i < l) then
begin
Exit(ENOMEM);
end;
Exit(0);
end;
function sysctl_new_user(req:p_sysctl_req;p:Pointer;l:QWORD):Integer;
var
error:Integer;
begin
if (req^.newptr=nil) then
begin
Exit(0);
end;
if ((req^.newlen - req^.newidx) < l) then
begin
Exit(EINVAL);
end;
error:=copyin(req^.newptr + req^.newidx, p, l);
Inc(req^.newidx,l);
Exit(error);
end;
//Exit(ENOTDIR);
//Exit(ENOENT);
function sysctl_kern_proc_idtable(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
begin
//get idtable key count
Exit(ENOENT); //sceSblACMgrIsSystemUcred
end;
function sysctl_kern_arandom(oidp:p_sysctl_oid;arg1:Pointer;arg2:ptrint;req:p_sysctl_req):Integer;
var
len:Integer;
data:array[0..254] of Byte;
begin
len:=256;
if (req^.oldlen < 256) then
begin
len:=req^.oldlen;
end;
arc4rand(@data,len,0);
Result:=SYSCTL_OUT(req,@data,len);
end;
function sysctl_kern_proc(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
Writeln(StdErr,'sysctl_kern_proc:',name[0]);
end;
function sysctl_kern(name:PInteger;namelen:DWORD;noid:p_sysctl_oid;req:p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOTDIR);
Result:=ENOENT;
case name[0] of
KERN_PROC:Result:=sysctl_kern_proc(name+1,namelen-1,noid,req);
KERN_ARND:Result:=SYSCTL_HANDLE(noid,@sysctl_kern_arandom);
else
begin
Writeln(StdErr,'Unhandled sysctl_kern:',name[0]);
end;
end;
end;
function sysctl_find_oid(name :PInteger;
namelen:DWORD;
noid :p_sysctl_oid;
req :p_sysctl_req):Integer;
begin
if (namelen=0) then Exit(ENOENT);
Result:=ENOENT;
case name[0] of
CTL_KERN:Result:=sysctl_kern(name+1,namelen-1,noid,req);
else
begin
Writeln(StdErr,'Unhandled sysctl_find_oid:',name[0]);
end;
end;
end;
function sysctl_root(oidp:p_sysctl_oid;
arg1:PInteger;
arg2:DWORD;
req :p_sysctl_req):Integer;
var
oid:t_sysctl_oid;
begin
oid:=Default(t_sysctl_oid);
Result:=sysctl_find_oid(arg1, arg2, @oid, req);
if (Result<>0) then Exit;
if (oid.oid_handler=nil) then Exit(EINVAL);
//if ((oid.oid_kind and CTLTYPE)=CTLTYPE_NODE) then
//begin
// arg1:=arg1 + indx;
// arg2:=arg2 - indx;
//end else
//begin
// arg1:=oid.oid_arg1;
// arg2:=oid.oid_arg2;
//end;
Result:=oid.oid_handler(@oid, arg1, arg2, req);
end;
function userland_sysctl(name :PInteger;
namelen :DWORD;
old :Pointer;
oldlenp :PQWORD;
inkernel:Integer;
new :Pointer;
newlen :QWORD;
retval :PQWORD;
flags :Integer):Integer;
var
error,memlocked:Integer;
req:t_sysctl_req;
begin
error:=0;
req:=Default(t_sysctl_req);
req.td :=curkthread;
req.flags:=flags;
if (oldlenp<>nil) then
begin
if (inkernel<>0) then
begin
req.oldlen:=oldlenp^;
end else
begin
error:=copyin(oldlenp, @req.oldlen, sizeof(Pointer));
if (error<>0) then Exit(error);
end;
end;
req.validlen:=req.oldlen;
if (old<>nil) then
begin
//if (!useracc(old, req.oldlen, VM_PROT_WRITE))
// Exit(EFAULT);
req.oldptr:=old;
end;
if (new<>nil) then
begin
//if (!useracc(new, newlen, VM_PROT_READ))
// Exit(EFAULT);
req.newlen:=newlen;
req.newptr:=new;
end;
req.oldfunc:=@sysctl_old_user;
req.newfunc:=@sysctl_new_user;
//req.lock:=REQ_UNWIRED;
if (req.oldlen > PAGE_SIZE) then
begin
memlocked:=1;
sx_xlock(@sysctlmemlock);
end else
begin
memlocked:=0;
end;
repeat
req.oldidx:=0;
req.newidx:=0;
SYSCTL_XLOCK();
error:=sysctl_root(nil, name, namelen, @req);
SYSCTL_XUNLOCK();
if (error<>EAGAIN) then
begin
break;
end;
//kern_yield(PRI_USER);
until false;
//if (req.lock=REQ_WIRED) and (req.validlen > 0) then
//begin
// vsunlock(req.oldptr, req.validlen);
//end;
if (memlocked<>0) then
begin
sx_xunlock(@sysctlmemlock);
end;
if (error<>0) and (error<>ENOMEM) then
begin
Exit(error);
end;
if (retval<>nil) then
begin
if (req.oldptr<>nil) and (req.oldidx > req.validlen) then
retval^:=req.validlen
else
retval^:=req.oldidx;
end;
Exit(error);
end;
function sys___sysctl(name :PInteger;
namelen:DWORD;
old :Pointer;
oldlenp:PQWORD;
new :Pointer;
newlen :QWORD):Integer;
var
error,i:Integer;
_name:array[0..CTL_MAXNAME-1] of Integer;
j:QWORD;
begin
if (namelen > CTL_MAXNAME) or (namelen < 2) then
begin
Exit(EINVAL);
end;
error:=copyin(name, @_name, namelen * sizeof(Integer));
if (error<>0) then Exit(error);
error:=userland_sysctl(@_name,
namelen,
old,
oldlenp,
0,
new,
newlen,
@j,
0);
if (error<>0) and (error<>ENOMEM) then
begin
Exit(error);
end;
if (oldlenp<>nil) then
begin
i:=copyout(@j, oldlenp, sizeof(j));
if (i<>0) then
begin
Exit(i);
end;
end;
Exit(error);
end;
end.

View File

@ -2044,6 +2044,8 @@ var
begin
Result:=nil;
Writeln(' do_load_object:',dynlib_basename(path));
new:=obj_new();
err:=self_load_shared_object(path,new,ord((flags and $20)<>0));
@ -2158,6 +2160,8 @@ var
begin
Assert(root^.ref_count=0,'unload_object ref_count');
Writeln(' unload_object:',dynlib_basename(root^.lib_path));
{
* Pass over the DAG removing unreferenced objects from
* appropriate lists.
@ -2225,7 +2229,7 @@ begin
begin
fname:='/'+fname;
end;
fname:=p_proc.p_randomized_path+fname;
fname:='/'+p_proc.p_randomized_path+fname;
if rtld_file_exists(pchar(fname)) then goto _do_load;

27
sys/md/md_arc4random.pas Normal file
View File

@ -0,0 +1,27 @@
unit md_arc4random;
{$mode ObjFPC}{$H+}
{$CALLING SysV_ABI_CDecl}
interface
procedure arc4rand(ptr:Pointer;len,reseed:Integer);
implementation
const
BCRYPT_USE_SYSTEM_PREFERRED_RNG=2;
function BCryptGenRandom(hAlgorithm:Pointer;
pbBuffer:PByte;
cbBuffer:DWORD;
dwFlags:DWORD):DWORD; stdcall; external 'Bcrypt';
procedure arc4rand(ptr:Pointer;len,reseed:Integer);
begin
BCryptGenRandom(nil,ptr,len,BCRYPT_USE_SYSTEM_PREFERRED_RNG);
end;
end.

View File

@ -13,6 +13,7 @@ uses
time,
kern_time,
subr_sleepqueue,
kern_sysctl,
kern_thr,
kern_thread,
kern_sig,
@ -74,6 +75,7 @@ procedure sys_init;
begin
timeinit;
init_sleepqueues;
sysctl_register_all;
PROC_INIT;
threadinit;
siginit;

View File

@ -90,6 +90,7 @@ function _fpathconf(fd,name:Integer):Integer;
function getrlimit(which:Integer;rlp:Pointer):Integer;
function setrlimit(which:Integer;rlp:Pointer):Integer;
function _getdirentries(fd:Integer;buf:Pointer;count:DWORD;basep:PInt64):Integer;
function __sysctl(name:PInteger;namelen:DWORD;old:Pointer;oldlenp:PQWORD;new:Pointer;newlen:QWORD):Integer;
function futimes(fd:Integer;tptr:Pointer):Integer;
function getpgid(pid:Integer):Integer;
function poll(fds:Pointer;nfds:DWORD;timeout:Integer):Integer;
@ -813,6 +814,13 @@ asm
jmp cerror
end;
function __sysctl(name:PInteger;namelen:DWORD;old:Pointer;oldlenp:PQWORD;new:Pointer;newlen:QWORD):Integer; assembler; nostackframe;
asm
movq $202,%rax
call fast_syscall
jmp cerror
end;
function futimes(fd:Integer;tptr:Pointer):Integer; assembler; nostackframe;
asm
movq $206,%rax

View File

@ -28,6 +28,7 @@ uses
kern_dynlib,
kern_ksched,
kern_rtprio,
kern_sysctl,
kern_thread,
sys_machdep,
kern_context,
@ -1062,7 +1063,7 @@ const
),
(//[202]
sy_narg:6;
sy_call:nil;
sy_call:@sys___sysctl;
sy_name:'sys___sysctl'
),
(//[203]

View File

@ -597,6 +597,14 @@
<Filename Value="..\kern\kern_stub.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\kern\kern_sysctl.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
<Unit>
<Filename Value="..\md\md_arc4random.pas"/>
<IsPartOfProject Value="True"/>
</Unit>
</Units>
</ProjectOptions>
<CompilerOptions>

View File

@ -91,7 +91,8 @@ uses
kern_timeout,
kern_exec,
kern_dynlib,
vmparam;
vmparam,
kern_sysctl;
const
PAGE_MAP_COUNT=(qword(VM_MAXUSER_ADDRESS) shr PAGE_SHIFT);

View File

@ -107,7 +107,8 @@ implementation
uses
vmparam,
vnode,
vfs_subr;
vfs_subr,
kern_patcher;
function IDX_TO_OFF(x:DWORD):QWORD; inline;
begin
@ -225,6 +226,8 @@ begin
Assert(obj^.paging_in_progress=0,'vm_object_terminate: pageout in progress');
vm_object_patch_remove(obj,0,0);
{
* Clean and free the pages, as appropriate. All references to the
* obj are gone, so we don't need to lock it.
@ -385,9 +388,7 @@ procedure vm_object_page_remove(obj:vm_object_t;
__end:vm_pindex_t;
options:Integer);
begin
//OBJPR_CLEANONLY=$1; // Don't remove dirty pages.
//OBJPR_NOTMAPPED=$2; // Don't unmap pages.
//OBJPR_NOTWIRED =$4; // Don't remove wired pages.
vm_object_patch_remove(obj,start,__end);
end;
{