Prevention of file direct memory reads in xnu kernel - Kauth doesn't enough
Prevention of file direct memory reads in xnu kernel - Kauth doesn't enough
- Subject: Prevention of file direct memory reads in xnu kernel - Kauth doesn't enough
- From: Irad K <email@hidden>
- Date: Thu, 05 Jul 2018 08:53:32 +0300
I've got a dylib file for which I prevent access in kernel level to any
other process but my own.
To achieve that, I use driver that listen to kauth vnode scope with
callback that prevent any access to this file by other process.
However, I've noticed that spindump coreSymbolication framework can bypass
this authorization flow after 4 retries to access the file (using open
syscall), and access the file memory directly as it can be shown in the
following backtrace :
------------------------------------------------------------------
-------------------------------------------------------
frame #2: 0xffffff7f87ac4784
IOStorageFamily`dkreadwrite(dkr=0xffffff8062fca3e0, dkrtype=<unavailable>)
at IOMediaBSDClient.cpp:2975 [opt]
frame #3: 0xffffff80072d8734 kernel`spec_strategy(ap=<unavailable>) at
spec_vnops.c:2409 [opt]
frame #4: 0xffffff8007282212 kernel`buf_strategy(devvp=<unavailable>,
ap=<unavailable>) at vfs_bio.c:1379 [opt]
frame #5: 0xffffff800728ad42 kernel`cluster_io [inlined]
VNOP_STRATEGY(bp=0xffffff8062fca3e0) at kpi_vfs.c:5696 [opt]
frame #6: 0xffffff800728ad0b kernel`cluster_io(vp=0xffffff80145a8c18,
upl=0xffffff80107f7700, upl_offset=0x0000000000004000, f_offset=40960,
non_rounded_size=0, flags=141, real_bp=<unavailable>,
iostate=<unavailable>, callback=<unavailable>, callback_arg=<unavailable>)
at vfs_cluster.c:1801 [opt]
frame #7: 0xffffff800728b8f5
kernel`cluster_pagein_ext(vp=0xffffff80145a8c18, upl=0xffffff80107f7700,
upl_offset=<unavailable>, f_offset=24576, size=<unavailable>,
filesize=-549414335464, flags=<unavailable>, callback=<unavailable>,
callback_arg=<unavailable>) at vfs_cluster.c:2171 [opt]
frame #8: 0xffffff800728b7e5 kernel`cluster_pagein(vp=<unavailable>,
upl=<unavailable>, upl_offset=<unavailable>, f_offset=<unavailable>,
size=<unavailable>, filesize=<unavailable>, flags=0) at vfs_cluster.c:2116
[opt]
frame #9: 0xffffff7f893d60be
frame #10: 0xffffff80075a811a kernel`vnode_pagein [inlined]
VNOP_PAGEIN(size=24576, flags=341478424, ctx=<unavailable>) at
kpi_vfs.c:5273 [opt]
frame #11: 0xffffff80075a80d3 kernel`vnode_pagein(vp=0xffffff80145a8c18,
upl=<unavailable>, upl_offset=<unavailable>, f_offset=24576,
size=<unavailable>, flags=341478424, errorp=<unavailable>) at
vnode_pager.c:593 [opt]
frame #12: 0xffffff80070dc119
kernel`vnode_pager_cluster_read(vnode_object=0xffffff80145a48e8,
base_offset=24576, offset=<unavailable>, io_streaming=<unavailable>,
cnt=0x0000000000004000) at bsd_vm.c:851 [opt]
frame #13: 0xffffff80070dbe93
kernel`vnode_pager_data_request(mem_obj=0xffffff80145a48e8, offset=24576,
length=<unavailable>, desired_access=<unavailable>,
fault_info=<unavailable>) at bsd_vm.c:639 [opt]
frame #14: 0xffffff80070eb011 kernel`vm_fault_page [inlined]
memory_object_data_request(memory_object=<unavailable>,
offset=<unavailable>, length=4096, desired_access=1,
fault_info=<unavailable>) at memory_object.c:2134 [opt]
frame #15: 0xffffff80070eaffb
kernel`vm_fault_page(first_object=0xffffff8011d64a00, first_offset=4096,
fault_type=1, must_be_resident=0, caller_lookup=0,
protection=0xffffff806717be90, result_page=<unavailable>,
top_page=<unavailable>, type_of_fault=<unavailable>,
error_code=<unavailable>, no_zero_fill=<unavailable>, data_supply=0,
fault_info=<unavailable>) at vm_fault.c:1770 [opt]
frame #16: 0xffffff80070ef82a kernel`vm_fault_internal(map=<unavailable>,
vaddr=<unavailable>, caller_prot=1, change_wiring=<unavailable>,
wire_tag=0, interruptible=2, caller_pmap=<unavailable>,
caller_pmap_addr=<unavailable>, physpage_p=<unavailable>) at
vm_fault.c:4610 [opt]
frame #17: 0xffffff8007188f92 kernel`user_trap [inlined]
vm_fault(map=<unavailable>, fault_type=<unavailable>, change_wiring=0,
wire_tag=0, interruptible=2, caller_pmap_addr=0) at vm_fault.c:3416 [opt]
frame #18: 0xffffff8007188f6f
kernel`user_trap(saved_state=0xffffff800f07b7a0) at trap.c:1083 [opt]
-------------------------------------------------------------------------------------------------------------------------
My question is how it's possible to get memory fault on the file memory
without open it first (kauth prevent open syscall). what system call can
actually initial the kernel thread whose backtrace listed above ?
B.S:
First I thought it might be mmap, but I eliminate this option after hooking
Mac policy function of mpo_file_check_mmap.
Then I tried to look at the trace of spindump when it reads my dylib. it
can clearly by shown that the open is failed for 4 times before somehow the
spindump manage to read my file.
perhaps any of the syscalls that triggered this memory read exists in
there, but which one ?
CODE: SELECT ALL
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
proc_info(0x2, 0x22C, 0x3) = 136 0
__mac_syscall(0x7FFF7C5FBAC6, 0x2, 0x70000E7AD6F0) = 0 0
proc_info(0x2, 0x22C, 0x3) = 136 0
proc_info(0x2, 0x22C, 0xB) = 0 0
proc_info(0x2, 0x22C, 0x3) = 136 0
proc_info(0x2, 0x1, 0x3) = 136 0
proc_info(0x2, 0x1, 0xB) = 0 0
bsdthread_create(0x7FFF682EDC18, 0x70000E7AE718, 0x80000) =
244015104 0
thread_selfid(0x0, 0x0, 0x0) = 10973 0
psynch_mutexdrop(0x70000E7AE728, 0x203, 0x100) = 0 0
psynch_mutexwait(0x70000E7AE728, 0x203, 0x0) = 515 0
__disable_threadsignal(0x1, 0x0, 0x0) = 0 0
__semwait_signal(0x1A2F, 0x0, 0x0) = 0 0
getattrlist("/Library/MyDir/MyFile.dylib\0", 0x70000E7ADEA0,
0x70000E7AE2A8) = 0 0
geteuid(0x0, 0x0, 0x0) = 0 0
bsdthread_create(0x7FFF682EDC18, 0x70000E7AE7E0, 0x80000) =
244015104 0
thread_selfid(0x0, 0x0, 0x0) = 10974 0
psynch_mutexdrop(0x70000E7AE7F0, 0x203, 0x100) = 0 0
psynch_mutexwait(0x70000E7AE7F0, 0x203, 0x0) = 515 0
geteuid(0x0, 0x0, 0x0) = 0 0
kevent_qos(0xFFFFFFFFFFFFFFFF, 0x70000E8B56B8, 0x1) = 0 0
workq_kernreturn(0x40, 0x70000E938B80, 0x1) = 0 Err#-2
workq_kernreturn(0x20, 0x0, 0x1) = 0 0
workq_kernreturn(0x4, 0x0, 0x0) = 0 Err#-2
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
open("/Library/MyDir/MyFile.dylib\0", 0x0, 0x0) = -1 Err#13
write_nocancel(0x2, "Caught EXC_BAD_ACCESS at 0x10bbc4d84, valid page
mapping, page query flags (0x80)\n\0", 0x52) = 82 0
__disable_threadsignal(0x1, 0x0, 0x0) = 0 0
__semwait_signal(0x227B, 0x0, 0x0) = 0 0
write_nocancel(0x2, "Missing page in pid 556, create of symbol owner data
for [/Library/MyDir/MyFile.dylib] failed, err code 4098\n\0", 0x81)
= 129 0
open_nocancel("/Library/MyDir\0", 0x1100004, 0xE7AD20A) = 4 0
fstatfs64(0x4, 0x70000E7AC028, 0x0) = 0 0
getdirentries64(0x4, 0x7FF8BDAF6800, 0x1000) = -1 Err#5
close_nocancel(0x4) = 0 0
stat64("/Library/MyDir\0", 0x70000E7ADAE0, 0x0) = 0 0
open_nocancel("/Library/MyDir\0", 0x1100004, 0xE7AD60A) = 4 0
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden