1*2c2f96dcSApple OSS DistributionsTask References 2*2c2f96dcSApple OSS Distributions=============== 3*2c2f96dcSApple OSS Distributions 4*2c2f96dcSApple OSS DistributionsFinding the source of task reference count leaks. 5*2c2f96dcSApple OSS Distributions 6*2c2f96dcSApple OSS DistributionsBackground 7*2c2f96dcSApple OSS Distributions---------- 8*2c2f96dcSApple OSS Distributions 9*2c2f96dcSApple OSS DistributionsTasks in XNU are reference counted. When a task is created it starts with two 10*2c2f96dcSApple OSS Distributionsreferences - one for the caller and one for the task itself. Over the lifetime 11*2c2f96dcSApple OSS Distributionsof the task this reference count is modified, for example when a thread is 12*2c2f96dcSApple OSS Distributionscreated it increments the reference count and when it exits that count drops. 13*2c2f96dcSApple OSS DistributionsWhen a reference count reaches zero, the task is freed. 14*2c2f96dcSApple OSS Distributions 15*2c2f96dcSApple OSS DistributionsTo grab a reference: 16*2c2f96dcSApple OSS Distributions```c 17*2c2f96dcSApple OSS Distributionstask_reference() 18*2c2f96dcSApple OSS Distributions``` 19*2c2f96dcSApple OSS Distributions 20*2c2f96dcSApple OSS DistributionsTo release a reference: 21*2c2f96dcSApple OSS Distributions```c 22*2c2f96dcSApple OSS Distributionstask_deallocate() 23*2c2f96dcSApple OSS Distributions``` 24*2c2f96dcSApple OSS Distributions 25*2c2f96dcSApple OSS DistributionsOne of the big problems seen with task references is that difficult to debug 26*2c2f96dcSApple OSS Distributions_leaks_ commonly occur. This happens when a reference is taken but never 27*2c2f96dcSApple OSS Distributionsreleased. The task is kept around indefinitely and eventually the system runs 28*2c2f96dcSApple OSS Distributionsout of a finite resource (for example ASIDs). At this point there is very little 29*2c2f96dcSApple OSS Distributionsinformation to determine what code was responsible for the leak. 30*2c2f96dcSApple OSS Distributions 31*2c2f96dcSApple OSS Distributions 32*2c2f96dcSApple OSS DistributionsTask Reference Groups 33*2c2f96dcSApple OSS Distributions-------------------- 34*2c2f96dcSApple OSS Distributions 35*2c2f96dcSApple OSS DistributionsReference groups are a feature which keep track of statistics (and when 36*2c2f96dcSApple OSS Distributionsconfigured backtrace information) for a set of references. Reference groups are 37*2c2f96dcSApple OSS Distributionshierarchical. To help with debugging the following task reference group 38*2c2f96dcSApple OSS Distributionshierarchy is used: 39*2c2f96dcSApple OSS Distributions 40*2c2f96dcSApple OSS Distributions``` 41*2c2f96dcSApple OSS Distributionstask 42*2c2f96dcSApple OSS Distributions -> task_internal 43*2c2f96dcSApple OSS Distributions -> task_local_internal 44*2c2f96dcSApple OSS Distributions -> task_kernel 45*2c2f96dcSApple OSS Distributions -> task_local_internal 46*2c2f96dcSApple OSS Distributions -> task_mig 47*2c2f96dcSApple OSS Distributions -> task_local_internal 48*2c2f96dcSApple OSS Distributions -> task_external 49*2c2f96dcSApple OSS Distributions -> task_local_external 50*2c2f96dcSApple OSS Distributions -> task_com.apple.security.sandbox 51*2c2f96dcSApple OSS Distributions -> task_com.apple.security.sandbox 52*2c2f96dcSApple OSS Distributions -> task_com.apple.driver.AppleHV 53*2c2f96dcSApple OSS Distributions -> task_com.apple.driver.AppleHV 54*2c2f96dcSApple OSS Distributions ... 55*2c2f96dcSApple OSS Distributions``` 56*2c2f96dcSApple OSS Distributions 57*2c2f96dcSApple OSS DistributionsThe `task` group contains a count of all task references in the system. The 58*2c2f96dcSApple OSS Distributionsfirst-level groups are static and sub-divide task references based on the 59*2c2f96dcSApple OSS Distributionssub-system they come from. `task_external` is used for kext references and each 60*2c2f96dcSApple OSS Distributionskext will be dynamically assigned a reference group as needed (if there's 61*2c2f96dcSApple OSS Distributionsone available). At the bottom level, there's a per-task (local) ref group under 62*2c2f96dcSApple OSS Distributionseach global group. 63*2c2f96dcSApple OSS DistributionsThe exact hierarchy of task references (specifically what per-task reference 64*2c2f96dcSApple OSS Distributionsgroups are created) changes depending on the 'task_refgrp' boot arg. 65*2c2f96dcSApple OSS Distributions 66*2c2f96dcSApple OSS DistributionsTask reference groups can be explored in `lldb` as follows: 67*2c2f96dcSApple OSS Distributions 68*2c2f96dcSApple OSS Distributions``` 69*2c2f96dcSApple OSS Distributions(lldb) showglobaltaskrefgrps 70*2c2f96dcSApple OSS Distributionsos_refgrp name count retain release log 71*2c2f96dcSApple OSS Distributions0xffffff801ace9250 task_kernel 68 367663 367595 0x0 72*2c2f96dcSApple OSS Distributions0xffffff801ace9288 task_internal 974 4953 3979 0x0 73*2c2f96dcSApple OSS Distributions0xffffff801ace92c0 task_mig 0 3670 3670 0x0 74*2c2f96dcSApple OSS Distributions0xffffff801ace9218 task_external 35 108 73 0x0 75*2c2f96dcSApple OSS Distributions0xffffff9369dc7b20 task_com.apple.iokit.IOAcceleratorFamily2 29 77 48 0x0 76*2c2f96dcSApple OSS Distributions0xffffff936a3f0a20 task_com.apple.iokit.CoreAnalyticsFamily 1 1 0 0x0 77*2c2f96dcSApple OSS Distributions0xffffff936a22cb20 task_com.apple.iokit.EndpointSecurity 0 1 1 0x0 78*2c2f96dcSApple OSS Distributions0xffffff936a283f60 task_com.apple.iokit.IOSurface 5 5 0 0x0 79*2c2f96dcSApple OSS Distributions0xffffff936a3f08a0 task_com.apple.security.sandbox 0 24 24 0x0 80*2c2f96dcSApple OSS Distributions 81*2c2f96dcSApple OSS Distributions``` 82*2c2f96dcSApple OSS Distributions 83*2c2f96dcSApple OSS DistributionsDisplay a task's reference groups: 84*2c2f96dcSApple OSS Distributions 85*2c2f96dcSApple OSS Distributions``` 86*2c2f96dcSApple OSS Distributions(lldb) showtaskrefgrps kernel_task 87*2c2f96dcSApple OSS Distributionsos_refgrp name count retain release log 88*2c2f96dcSApple OSS Distributions0xffffff936a4b9200 task_local_kernel 1 6 5 0x0 89*2c2f96dcSApple OSS Distributions0xffffff936a4b9238 task_local_internal 132 619 487 0x0 90*2c2f96dcSApple OSS Distributions``` 91*2c2f96dcSApple OSS Distributions 92*2c2f96dcSApple OSS DistributionsThe reference group hierarchy for a specific group can be displayed as follows: 93*2c2f96dcSApple OSS Distributions 94*2c2f96dcSApple OSS Distributions``` 95*2c2f96dcSApple OSS Distributions(lldb) showosrefgrphierarchy 0xffffff936a3f08a0 96*2c2f96dcSApple OSS Distributions0xffffff801ace9988 all 1121 377740 376619 0x0 97*2c2f96dcSApple OSS Distributions0xffffff801ace91e0 task 1077 376394 375317 0x0 98*2c2f96dcSApple OSS Distributions0xffffff801ace9218 task_external 35 108 73 0x0 99*2c2f96dcSApple OSS Distributions0xffffff936a3f08a0 task_com.apple.security.sandbox 0 24 24 0x0 100*2c2f96dcSApple OSS Distributions``` 101*2c2f96dcSApple OSS Distributions 102*2c2f96dcSApple OSS DistributionsReference groups are normally disabled, but task reference group statistics 103*2c2f96dcSApple OSS Distributions*are* enabled by default (for `RELEASE` builds, reference groups are not available 104*2c2f96dcSApple OSS Distributionsat all). Backtrace logging for all groups is disabled, including task reference 105*2c2f96dcSApple OSS Distributionsgroups. To enable backtrace logging and reference group statistics, the `rlog` 106*2c2f96dcSApple OSS Distributionsboot-arg must be used. Backtrace logging for task reference groups is only 107*2c2f96dcSApple OSS Distributionsenabled when `rlog` has been set to a suitable value. 108*2c2f96dcSApple OSS Distributions 109*2c2f96dcSApple OSS DistributionsFor example 110*2c2f96dcSApple OSS Distributions 111*2c2f96dcSApple OSS DistributionsTo enable statistics for all reference groups and backtrace logging for the 112*2c2f96dcSApple OSS Distributions*task_external* reference group in particular: 113*2c2f96dcSApple OSS Distributions 114*2c2f96dcSApple OSS Distributions``` 115*2c2f96dcSApple OSS Distributionsnvram boot-args="rlog=task_external ..." 116*2c2f96dcSApple OSS Distributions``` 117*2c2f96dcSApple OSS Distributions 118*2c2f96dcSApple OSS Distributions``` 119*2c2f96dcSApple OSS Distributions(lldb) showglobaltaskrefgrps 120*2c2f96dcSApple OSS Distributionsos_refgrp name count retain release log 121*2c2f96dcSApple OSS Distributions0xffffff801e0e9250 task_kernel 1259 132739 131480 0x0 122*2c2f96dcSApple OSS Distributions0xffffff801e0e9218 task_external 35 100 65 0xffffffa05b3fc000 123*2c2f96dcSApple OSS Distributions0xffffff936d117be0 task_com.apple.iokit.IOAcceleratorFamily2 29 77 48 0x0 124*2c2f96dcSApple OSS Distributions0xffffff936db9fa20 task_com.apple.iokit.CoreAnalyticsFamily 1 1 0 0x0 125*2c2f96dcSApple OSS Distributions0xffffff936d9dbb20 task_com.apple.iokit.EndpointSecurity 0 1 1 0x0 126*2c2f96dcSApple OSS Distributions0xffffff936da324e0 task_com.apple.iokit.IOSurface 5 5 0 0x0 127*2c2f96dcSApple OSS Distributions0xffffff936db9f8a0 task_com.apple.security.sandbox 0 16 16 0x0 128*2c2f96dcSApple OSS Distributions 129*2c2f96dcSApple OSS Distributions 130*2c2f96dcSApple OSS Distributions(lldb) showbtlogrecords 0xffffffa05b3fc000 131*2c2f96dcSApple OSS Distributions-------- OP 1 Stack Index 0 with active refs 1 of 165 -------- 132*2c2f96dcSApple OSS Distributions0xffffff801da7c1cb <kernel.development`ref_log_op at refcnt.c:107> 133*2c2f96dcSApple OSS Distributions0xffffff801d27c35d <kernel.development`task_reference_grp at task_ref.c:274> 134*2c2f96dcSApple OSS Distributions0xffffff801ecc014e <EndpointSecurity`VMMap::taskSelf()> 135*2c2f96dcSApple OSS Distributions0xffffff801eccc845 <EndpointSecurity`EndpointSecurityClient::create(ScopedPointer<MachSendWrapper> const&, proc*, ScopedPointer<EndpointSecurityExternalClient> const&, es_client_config_t const&)> 136*2c2f96dcSApple OSS Distributions... 137*2c2f96dcSApple OSS Distributions``` 138