diff --git a/sys/kern/kern_patcher.pas b/sys/kern/kern_patcher.pas index c56c8e2c..f38a8917 100644 --- a/sys/kern/kern_patcher.pas +++ b/sys/kern/kern_patcher.pas @@ -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] diff --git a/sys/kern/kern_reloc.pas b/sys/kern/kern_reloc.pas index 923a66e3..4dce5609 100644 --- a/sys/kern/kern_reloc.pas +++ b/sys/kern/kern_reloc.pas @@ -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 diff --git a/sys/kern/kern_rtld.pas b/sys/kern/kern_rtld.pas index ebad31f9..40cd7b10 100644 --- a/sys/kern/kern_rtld.pas +++ b/sys/kern/kern_rtld.pas @@ -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. diff --git a/sys/kern/kern_sysctl.pas b/sys/kern/kern_sysctl.pas new file mode 100644 index 00000000..fdd1c193 --- /dev/null +++ b/sys/kern/kern_sysctl.pas @@ -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. + diff --git a/sys/kern/subr_dynlib.pas b/sys/kern/subr_dynlib.pas index 4b057d52..ebdd4d0e 100644 --- a/sys/kern/subr_dynlib.pas +++ b/sys/kern/subr_dynlib.pas @@ -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; diff --git a/sys/md/md_arc4random.pas b/sys/md/md_arc4random.pas new file mode 100644 index 00000000..c084b592 --- /dev/null +++ b/sys/md/md_arc4random.pas @@ -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. + diff --git a/sys/sys_sysinit.pas b/sys/sys_sysinit.pas index cc14fb0e..f0f696b2 100644 --- a/sys/sys_sysinit.pas +++ b/sys/sys_sysinit.pas @@ -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; diff --git a/sys/syscalls.pas b/sys/syscalls.pas index cf84c8bb..3d0708be 100644 --- a/sys/syscalls.pas +++ b/sys/syscalls.pas @@ -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 diff --git a/sys/sysent.pas b/sys/sysent.pas index d3dd405e..12d3484c 100644 --- a/sys/sysent.pas +++ b/sys/sysent.pas @@ -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] diff --git a/sys/test/project1.lpi b/sys/test/project1.lpi index 49e81b43..5928abb9 100644 --- a/sys/test/project1.lpi +++ b/sys/test/project1.lpi @@ -597,6 +597,14 @@ + + + + + + + + diff --git a/sys/test/project1.lpr b/sys/test/project1.lpr index a37c4c7f..95013c87 100644 --- a/sys/test/project1.lpr +++ b/sys/test/project1.lpr @@ -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); diff --git a/sys/vm/vm_object.pas b/sys/vm/vm_object.pas index 3b6e91d4..dd96b3f6 100644 --- a/sys/vm/vm_object.pas +++ b/sys/vm/vm_object.pas @@ -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; {