CINXE.COM

Project Zero: April 2021

<!DOCTYPE html> <html class='v2' dir='ltr' lang='en' xmlns='http://www.w3.org/1999/xhtml' xmlns:b='http://www.google.com/2005/gml/b' xmlns:data='http://www.google.com/2005/gml/data' xmlns:expr='http://www.google.com/2005/gml/expr'> <head> <link href='https://www.blogger.com/static/v1/widgets/3566091532-css_bundle_v2.css' rel='stylesheet' type='text/css'/> <meta content='width=1100' name='viewport'/> <meta content='text/html; charset=UTF-8' http-equiv='Content-Type'/> <meta content='blogger' name='generator'/> <link href='https://googleprojectzero.blogspot.com/favicon.ico' rel='icon' type='image/x-icon'/> <link href='https://googleprojectzero.blogspot.com/2021/04/' rel='canonical'/> <link rel="alternate" type="application/atom+xml" title="Project Zero - Atom" href="https://googleprojectzero.blogspot.com/feeds/posts/default" /> <link rel="alternate" type="application/rss+xml" title="Project Zero - RSS" href="https://googleprojectzero.blogspot.com/feeds/posts/default?alt=rss" /> <link rel="service.post" type="application/atom+xml" title="Project Zero - Atom" href="https://www.blogger.com/feeds/4838136820032157985/posts/default" /> <!--Can't find substitution for tag [blog.ieCssRetrofitLinks]--> <meta content='https://googleprojectzero.blogspot.com/2021/04/' property='og:url'/> <meta content='Project Zero' property='og:title'/> <meta content='News and updates from the Project Zero team at Google' property='og:description'/> <title>Project Zero: April 2021</title> <style type='text/css'>@font-face{font-family:'Open Sans';font-style:normal;font-weight:400;font-stretch:normal;font-display:swap;src:url(//fonts.gstatic.com/s/opensans/v40/memSYaGs126MiZpBA-UvWbX2vVnXBbObj2OVZyOOSr4dVJWUgsjZ0B4gaVY.eot);}</style> <style id='page-skin-1' type='text/css'><!-- /* ----------------------------------------------- Blogger Template Style Name: Simple Designer: Blogger URL: www.blogger.com ----------------------------------------------- */ /* Variable definitions ==================== <Variable name="keycolor" description="Main Color" type="color" default="#66bbdd"/> <Group description="Page Text" selector="body"> <Variable name="body.font" description="Font" type="font" default="normal normal 12px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="body.text.color" description="Text Color" type="color" default="#222222"/> </Group> <Group description="Backgrounds" selector=".body-fauxcolumns-outer"> <Variable name="body.background.color" description="Outer Background" type="color" default="#66bbdd"/> <Variable name="content.background.color" description="Main Background" type="color" default="#ffffff"/> <Variable name="header.background.color" description="Header Background" type="color" default="transparent"/> </Group> <Group description="Links" selector=".main-outer"> <Variable name="link.color" description="Link Color" type="color" default="#2288bb"/> <Variable name="link.visited.color" description="Visited Color" type="color" default="#888888"/> <Variable name="link.hover.color" description="Hover Color" type="color" default="#33aaff"/> </Group> <Group description="Blog Title" selector=".header h1"> <Variable name="header.font" description="Font" type="font" default="normal normal 60px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="header.text.color" description="Title Color" type="color" default="#3399bb" /> </Group> <Group description="Blog Description" selector=".header .description"> <Variable name="description.text.color" description="Description Color" type="color" default="#777777" /> </Group> <Group description="Tabs Text" selector=".tabs-inner .widget li a"> <Variable name="tabs.font" description="Font" type="font" default="normal normal 14px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="tabs.text.color" description="Text Color" type="color" default="#999999"/> <Variable name="tabs.selected.text.color" description="Selected Color" type="color" default="#000000"/> </Group> <Group description="Tabs Background" selector=".tabs-outer .PageList"> <Variable name="tabs.background.color" description="Background Color" type="color" default="#f5f5f5"/> <Variable name="tabs.selected.background.color" description="Selected Color" type="color" default="#eeeeee"/> </Group> <Group description="Post Title" selector="h3.post-title, .comments h4"> <Variable name="post.title.font" description="Font" type="font" default="normal normal 22px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> </Group> <Group description="Date Header" selector=".date-header"> <Variable name="date.header.color" description="Text Color" type="color" default="#000000"/> <Variable name="date.header.background.color" description="Background Color" type="color" default="transparent"/> <Variable name="date.header.font" description="Text Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="date.header.padding" description="Date Header Padding" type="string" default="inherit"/> <Variable name="date.header.letterspacing" description="Date Header Letter Spacing" type="string" default="inherit"/> <Variable name="date.header.margin" description="Date Header Margin" type="string" default="inherit"/> </Group> <Group description="Post Footer" selector=".post-footer"> <Variable name="post.footer.text.color" description="Text Color" type="color" default="#666666"/> <Variable name="post.footer.background.color" description="Background Color" type="color" default="#f9f9f9"/> <Variable name="post.footer.border.color" description="Shadow Color" type="color" default="#eeeeee"/> </Group> <Group description="Gadgets" selector="h2"> <Variable name="widget.title.font" description="Title Font" type="font" default="normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif"/> <Variable name="widget.title.text.color" description="Title Color" type="color" default="#000000"/> <Variable name="widget.alternate.text.color" description="Alternate Color" type="color" default="#999999"/> </Group> <Group description="Images" selector=".main-inner"> <Variable name="image.background.color" description="Background Color" type="color" default="#ffffff"/> <Variable name="image.border.color" description="Border Color" type="color" default="#eeeeee"/> <Variable name="image.text.color" description="Caption Text Color" type="color" default="#000000"/> </Group> <Group description="Accents" selector=".content-inner"> <Variable name="body.rule.color" description="Separator Line Color" type="color" default="#eeeeee"/> <Variable name="tabs.border.color" description="Tabs Border Color" type="color" default="transparent"/> </Group> <Variable name="body.background" description="Body Background" type="background" color="#eeeeee" default="$(color) none repeat scroll top left"/> <Variable name="body.background.override" description="Body Background Override" type="string" default=""/> <Variable name="body.background.gradient.cap" description="Body Gradient Cap" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="body.background.gradient.tile" description="Body Gradient Tile" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/body_gradient_tile_light.png)"/> <Variable name="content.background.color.selector" description="Content Background Color Selector" type="string" default=".content-inner"/> <Variable name="content.padding" description="Content Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.padding.horizontal" description="Content Horizontal Padding" type="length" default="10px" min="0" max="100px"/> <Variable name="content.shadow.spread" description="Content Shadow Spread" type="length" default="40px" min="0" max="100px"/> <Variable name="content.shadow.spread.webkit" description="Content Shadow Spread (WebKit)" type="length" default="5px" min="0" max="100px"/> <Variable name="content.shadow.spread.ie" description="Content Shadow Spread (IE)" type="length" default="10px" min="0" max="100px"/> <Variable name="main.border.width" description="Main Border Width" type="length" default="0" min="0" max="10px"/> <Variable name="header.background.gradient" description="Header Gradient" type="url" default="none"/> <Variable name="header.shadow.offset.left" description="Header Shadow Offset Left" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.offset.top" description="Header Shadow Offset Top" type="length" default="-1px" min="-50px" max="50px"/> <Variable name="header.shadow.spread" description="Header Shadow Spread" type="length" default="1px" min="0" max="100px"/> <Variable name="header.padding" description="Header Padding" type="length" default="30px" min="0" max="100px"/> <Variable name="header.border.size" description="Header Border Size" type="length" default="1px" min="0" max="10px"/> <Variable name="header.bottom.border.size" description="Header Bottom Border Size" type="length" default="1px" min="0" max="10px"/> <Variable name="header.border.horizontalsize" description="Header Horizontal Border Size" type="length" default="0" min="0" max="10px"/> <Variable name="description.text.size" description="Description Text Size" type="string" default="140%"/> <Variable name="tabs.margin.top" description="Tabs Margin Top" type="length" default="0" min="0" max="100px"/> <Variable name="tabs.margin.side" description="Tabs Side Margin" type="length" default="30px" min="0" max="100px"/> <Variable name="tabs.background.gradient" description="Tabs Background Gradient" type="url" default="url(https://resources.blogblog.com/blogblog/data/1kt/simple/gradients_light.png)"/> <Variable name="tabs.border.width" description="Tabs Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="tabs.bevel.border.width" description="Tabs Bevel Border Width" type="length" default="1px" min="0" max="10px"/> <Variable name="post.margin.bottom" description="Post Bottom Margin" type="length" default="25px" min="0" max="100px"/> <Variable name="image.border.small.size" description="Image Border Small Size" type="length" default="2px" min="0" max="10px"/> <Variable name="image.border.large.size" description="Image Border Large Size" type="length" default="5px" min="0" max="10px"/> <Variable name="page.width.selector" description="Page Width Selector" type="string" default=".region-inner"/> <Variable name="page.width" description="Page Width" type="string" default="auto"/> <Variable name="main.section.margin" description="Main Section Margin" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding" description="Main Padding" type="length" default="15px" min="0" max="100px"/> <Variable name="main.padding.top" description="Main Padding Top" type="length" default="30px" min="0" max="100px"/> <Variable name="main.padding.bottom" description="Main Padding Bottom" type="length" default="30px" min="0" max="100px"/> <Variable name="paging.background" color="#ffffff" description="Background of blog paging area" type="background" default="transparent none no-repeat scroll top center"/> <Variable name="footer.bevel" description="Bevel border length of footer" type="length" default="0" min="0" max="10px"/> <Variable name="mobile.background.overlay" description="Mobile Background Overlay" type="string" default="transparent none repeat scroll top left"/> <Variable name="mobile.background.size" description="Mobile Background Size" type="string" default="auto"/> <Variable name="mobile.button.color" description="Mobile Button Color" type="color" default="#ffffff" /> <Variable name="startSide" description="Side where text starts in blog language" type="automatic" default="left"/> <Variable name="endSide" description="Side where text ends in blog language" type="automatic" default="right"/> */ /* Content ----------------------------------------------- */ body { font: normal normal 12px Open Sans; color: #000000; background: #eeeeee none repeat scroll top left; padding: 0 0 0 0; } html body .region-inner { min-width: 0; max-width: 100%; width: auto; } h2 { font-size: 22px; } a:link { text-decoration:none; color: #2288bb; } a:visited { text-decoration:none; color: #888888; } a:hover { text-decoration:underline; color: #33aaff; } .body-fauxcolumn-outer .fauxcolumn-inner { background: transparent none repeat scroll top left; _background-image: none; } .body-fauxcolumn-outer .cap-top { position: absolute; z-index: 1; height: 400px; width: 100%; } .body-fauxcolumn-outer .cap-top .cap-left { width: 100%; background: transparent none repeat-x scroll top left; _background-image: none; } .content-outer { -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .15); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .15); -goog-ms-box-shadow: 0 0 0 #333333; box-shadow: 0 0 0 rgba(0, 0, 0, .15); margin-bottom: 1px; } .content-inner { padding: 10px 40px; } .content-inner { background-color: #ffffff; } /* Header ----------------------------------------------- */ .header-outer { background: transparent none repeat-x scroll 0 -400px; _background-image: none; } .Header h1 { font: normal normal 40px Open Sans; color: #000000; text-shadow: 0 0 0 rgba(0, 0, 0, .2); } .Header h1 a { color: #000000; } .Header .description { font-size: 18px; color: #000000; } .header-inner .Header .titlewrapper { padding: 22px 0; } .header-inner .Header .descriptionwrapper { padding: 0 0; } /* Tabs ----------------------------------------------- */ .tabs-inner .section:first-child { border-top: 0 solid #dddddd; } .tabs-inner .section:first-child ul { margin-top: -1px; border-top: 1px solid #dddddd; border-left: 1px solid #dddddd; border-right: 1px solid #dddddd; } .tabs-inner .widget ul { background: transparent none repeat-x scroll 0 -800px; _background-image: none; border-bottom: 1px solid #dddddd; margin-top: 0; margin-left: -30px; margin-right: -30px; } .tabs-inner .widget li a { display: inline-block; padding: .6em 1em; font: normal normal 12px Open Sans; color: #000000; border-left: 1px solid #ffffff; border-right: 1px solid #dddddd; } .tabs-inner .widget li:first-child a { border-left: none; } .tabs-inner .widget li.selected a, .tabs-inner .widget li a:hover { color: #000000; background-color: #eeeeee; text-decoration: none; } /* Columns ----------------------------------------------- */ .main-outer { border-top: 0 solid transparent; } .fauxcolumn-left-outer .fauxcolumn-inner { border-right: 1px solid transparent; } .fauxcolumn-right-outer .fauxcolumn-inner { border-left: 1px solid transparent; } /* Headings ----------------------------------------------- */ div.widget > h2, div.widget h2.title { margin: 0 0 1em 0; font: normal bold 11px 'Trebuchet MS',Trebuchet,Verdana,sans-serif; color: #000000; } /* Widgets ----------------------------------------------- */ .widget .zippy { color: #999999; text-shadow: 2px 2px 1px rgba(0, 0, 0, .1); } .widget .popular-posts ul { list-style: none; } /* Posts ----------------------------------------------- */ h2.date-header { font: normal bold 11px Arial, Tahoma, Helvetica, FreeSans, sans-serif; } .date-header span { background-color: #bbbbbb; color: #ffffff; padding: 0.4em; letter-spacing: 3px; margin: inherit; } .main-inner { padding-top: 35px; padding-bottom: 65px; } .main-inner .column-center-inner { padding: 0 0; } .main-inner .column-center-inner .section { margin: 0 1em; } .post { margin: 0 0 45px 0; } h3.post-title, .comments h4 { font: normal normal 22px Open Sans; margin: .75em 0 0; } .post-body { font-size: 110%; line-height: 1.4; position: relative; } .post-body img, .post-body .tr-caption-container, .Profile img, .Image img, .BlogList .item-thumbnail img { padding: 2px; background: #ffffff; border: 1px solid #eeeeee; -moz-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); -webkit-box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); box-shadow: 1px 1px 5px rgba(0, 0, 0, .1); } .post-body img, .post-body .tr-caption-container { padding: 5px; } .post-body .tr-caption-container { color: #666666; } .post-body .tr-caption-container img { padding: 0; background: transparent; border: none; -moz-box-shadow: 0 0 0 rgba(0, 0, 0, .1); -webkit-box-shadow: 0 0 0 rgba(0, 0, 0, .1); box-shadow: 0 0 0 rgba(0, 0, 0, .1); } .post-header { margin: 0 0 1.5em; line-height: 1.6; font-size: 90%; } .post-footer { margin: 20px -2px 0; padding: 5px 10px; color: #666666; background-color: #eeeeee; border-bottom: 1px solid #eeeeee; line-height: 1.6; font-size: 90%; } #comments .comment-author { padding-top: 1.5em; border-top: 1px solid transparent; background-position: 0 1.5em; } #comments .comment-author:first-child { padding-top: 0; border-top: none; } .avatar-image-container { margin: .2em 0 0; } #comments .avatar-image-container img { border: 1px solid #eeeeee; } /* Comments ----------------------------------------------- */ .comments .comments-content .icon.blog-author { background-repeat: no-repeat; background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAAZiS0dEAP8A/wD/oL2nkwAAAAlwSFlzAAALEgAACxIB0t1+/AAAAAd0SU1FB9sLFwMeCjjhcOMAAAD+SURBVDjLtZSvTgNBEIe/WRRnm3U8RC1neQdsm1zSBIU9VVF1FkUguQQsD9ITmD7ECZIJSE4OZo9stoVjC/zc7ky+zH9hXwVwDpTAWWLrgS3QAe8AZgaAJI5zYAmc8r0G4AHYHQKVwII8PZrZFsBFkeRCABYiMh9BRUhnSkPTNCtVXYXURi1FpBDgArj8QU1eVXUzfnjv7yP7kwu1mYrkWlU33vs1QNu2qU8pwN0UpKoqokjWwCztrMuBhEhmh8bD5UDqur75asbcX0BGUB9/HAMB+r32hznJgXy2v0sGLBcyAJ1EK3LFcbo1s91JeLwAbwGYu7TP/3ZGfnXYPgAVNngtqatUNgAAAABJRU5ErkJggg==); } .comments .comments-content .loadmore a { border-top: 1px solid #999999; border-bottom: 1px solid #999999; } .comments .comment-thread.inline-thread { background-color: #eeeeee; } .comments .continue { border-top: 2px solid #999999; } /* Accents ---------------------------------------------- */ .section-columns td.columns-cell { border-left: 1px solid transparent; } .blog-pager { background: transparent url(//www.blogblog.com/1kt/simple/paging_dot.png) repeat-x scroll top center; } .blog-pager-older-link, .home-link, .blog-pager-newer-link { background-color: #ffffff; padding: 5px; } .footer-outer { border-top: 1px dashed #bbbbbb; } /* Mobile ----------------------------------------------- */ body.mobile { background-size: auto; } .mobile .body-fauxcolumn-outer { background: transparent none repeat scroll top left; } .mobile .body-fauxcolumn-outer .cap-top { background-size: 100% auto; } .mobile .content-outer { -webkit-box-shadow: 0 0 3px rgba(0, 0, 0, .15); box-shadow: 0 0 3px rgba(0, 0, 0, .15); } .mobile .tabs-inner .widget ul { margin-left: 0; margin-right: 0; } .mobile .post { margin: 0; } .mobile .main-inner .column-center-inner .section { margin: 0; } .mobile .date-header span { padding: 0.1em 10px; margin: 0 -10px; } .mobile h3.post-title { margin: 0; } .mobile .blog-pager { background: transparent none no-repeat scroll top center; } .mobile .footer-outer { border-top: none; } .mobile .main-inner, .mobile .footer-inner { background-color: #ffffff; } .mobile-index-contents { color: #000000; } .mobile-link-button { background-color: #2288bb; } .mobile-link-button a:link, .mobile-link-button a:visited { color: #ffffff; } .mobile .tabs-inner .section:first-child { border-top: none; } .mobile .tabs-inner .PageList .widget-content { background-color: #eeeeee; color: #000000; border-top: 1px solid #dddddd; border-bottom: 1px solid #dddddd; } .mobile .tabs-inner .PageList .widget-content .pagelist-arrow { border-left: 1px solid #dddddd; } --></style> <style id='template-skin-1' type='text/css'><!-- body { min-width: 1120px; } .content-outer, .content-fauxcolumn-outer, .region-inner { min-width: 1120px; max-width: 1120px; _width: 1120px; } .main-inner .columns { padding-left: 0; padding-right: 310px; } .main-inner .fauxcolumn-center-outer { left: 0; right: 310px; /* IE6 does not respect left and right together */ _width: expression(this.parentNode.offsetWidth - parseInt("0") - parseInt("310px") + 'px'); } .main-inner .fauxcolumn-left-outer { width: 0; } .main-inner .fauxcolumn-right-outer { width: 310px; } .main-inner .column-left-outer { width: 0; right: 100%; margin-left: -0; } .main-inner .column-right-outer { width: 310px; margin-right: -310px; } #layout { min-width: 0; } #layout .content-outer { min-width: 0; width: 800px; } #layout .region-inner { min-width: 0; width: auto; } body#layout div.add_widget { padding: 8px; } body#layout div.add_widget a { margin-left: 32px; } --></style> <script type='text/javascript'> (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','https://www.google-analytics.com/analytics.js','ga'); ga('create', 'UA-240546891-1', 'auto', 'blogger'); ga('blogger.send', 'pageview'); </script> <link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=4838136820032157985&amp;zx=89189630-7e30-43b5-91d3-8fdab32d43bc' media='none' onload='if(media!=&#39;all&#39;)media=&#39;all&#39;' rel='stylesheet'/><noscript><link href='https://www.blogger.com/dyn-css/authorization.css?targetBlogID=4838136820032157985&amp;zx=89189630-7e30-43b5-91d3-8fdab32d43bc' rel='stylesheet'/></noscript> <meta name='google-adsense-platform-account' content='ca-host-pub-1556223355139109'/> <meta name='google-adsense-platform-domain' content='blogspot.com'/> </head> <body class='loading'> <div class='navbar section' id='navbar' name='Navbar'><div class='widget Navbar' data-version='1' id='Navbar1'><script type="text/javascript"> function setAttributeOnload(object, attribute, val) { if(window.addEventListener) { window.addEventListener('load', function(){ object[attribute] = val; }, false); } else { window.attachEvent('onload', function(){ object[attribute] = val; }); } } </script> <div id="navbar-iframe-container"></div> <script type="text/javascript" src="https://apis.google.com/js/platform.js"></script> <script type="text/javascript"> gapi.load("gapi.iframes:gapi.iframes.style.bubble", function() { if (gapi.iframes && gapi.iframes.getContext) { gapi.iframes.getContext().openChild({ url: 'https://www.blogger.com/navbar.g?targetBlogID\x3d4838136820032157985\x26blogName\x3dProject+Zero\x26publishMode\x3dPUBLISH_MODE_BLOGSPOT\x26navbarType\x3dLIGHT\x26layoutType\x3dLAYOUTS\x26searchRoot\x3dhttps://googleprojectzero.blogspot.com/search\x26blogLocale\x3den\x26v\x3d2\x26homepageUrl\x3dhttps://googleprojectzero.blogspot.com/\x26vt\x3d7568236161501195533', where: document.getElementById("navbar-iframe-container"), id: "navbar-iframe", messageHandlersFilter: gapi.iframes.CROSS_ORIGIN_IFRAMES_FILTER, messageHandlers: { 'blogger-ping': function() {} } }); } }); </script><script type="text/javascript"> (function() { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = '//pagead2.googlesyndication.com/pagead/js/google_top_exp.js'; var head = document.getElementsByTagName('head')[0]; if (head) { head.appendChild(script); }})(); </script> </div></div> <div class='body-fauxcolumns'> <div class='fauxcolumn-outer body-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content'> <div class='content-fauxcolumns'> <div class='fauxcolumn-outer content-fauxcolumn-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <div class='content-outer'> <div class='content-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left content-fauxborder-left'> <div class='fauxborder-right content-fauxborder-right'></div> <div class='content-inner'> <header> <div class='header-outer'> <div class='header-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left header-fauxborder-left'> <div class='fauxborder-right header-fauxborder-right'></div> <div class='region-inner header-inner'> <div class='header section' id='header' name='Header'><div class='widget Header' data-version='1' id='Header1'> <div id='header-inner'> <div class='titlewrapper'> <h1 class='title'> <a href='https://googleprojectzero.blogspot.com/'> Project Zero </a> </h1> </div> <div class='descriptionwrapper'> <p class='description'><span>News and updates from the Project Zero team at Google</span></p> </div> </div> </div></div> </div> </div> <div class='header-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </header> <div class='tabs-outer'> <div class='tabs-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left tabs-fauxborder-left'> <div class='fauxborder-right tabs-fauxborder-right'></div> <div class='region-inner tabs-inner'> <div class='tabs no-items section' id='crosscol' name='Cross-Column'></div> <div class='tabs no-items section' id='crosscol-overflow' name='Cross-Column 2'></div> </div> </div> <div class='tabs-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='main-outer'> <div class='main-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left main-fauxborder-left'> <div class='fauxborder-right main-fauxborder-right'></div> <div class='region-inner main-inner'> <div class='columns fauxcolumns'> <div class='fauxcolumn-outer fauxcolumn-center-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-left-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <div class='fauxcolumn-outer fauxcolumn-right-outer'> <div class='cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left'> <div class='fauxborder-right'></div> <div class='fauxcolumn-inner'> </div> </div> <div class='cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <!-- corrects IE6 width calculation --> <div class='columns-inner'> <div class='column-center-outer'> <div class='column-center-inner'> <div class='main section' id='main' name='Main'><div class='widget Blog' data-version='1' id='Blog1'> <div class='blog-posts hfeed'> <div class="date-outer"> <h2 class='date-header'><span>Thursday, April 22, 2021</span></h2> <div class="date-posts"> <div class='post-outer'> <div class='post hentry uncustomized-post-template' itemprop='blogPost' itemscope='itemscope' itemtype='http://schema.org/BlogPosting'> <meta content='https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixaqhrlPJxgqVridccvdElpi6yxaoJCSUXDp5q8hm_F66e5WHW3NRaFwmy-OWQvCKz661k3LEfi4A4r2sa1LkgMb8pu8CEVjKbzTkblc8SZZYcOsKkw7u0uG2qo5KzCdjbxixJ-CplQI2nohuVE1_t07PiNW-xRxnW-3e4WtILcCE6CoYjbN1D6UPi/s623/image3%282%29.png' itemprop='image_url'/> <meta content='4838136820032157985' itemprop='blogId'/> <meta content='2714099021755665939' itemprop='postId'/> <a name='2714099021755665939'></a> <h3 class='post-title entry-title' itemprop='name'> <a href='https://googleprojectzero.blogspot.com/2021/04/designing-sockfuzzer-network-syscall.html'>Designing sockfuzzer, a network syscall fuzzer for XNU</a> </h3> <div class='post-header'> <div class='post-header-line-1'></div> </div> <div class='post-body entry-content' id='post-body-2714099021755665939' itemprop='description articleBody'> <style type="text/css">@import url('https://themes.googleusercontent.com/fonts/css?kit=lhDjYqiy3mZ0x6ROQEUoUw');.lst-kix_pr131atimb8l-1>li:before{content:"\0025cb "}.lst-kix_pr131atimb8l-0>li:before{content:"\0025cf "}.lst-kix_pr131atimb8l-3>li:before{content:"\0025cf "}.lst-kix_pr131atimb8l-2>li:before{content:"\0025a0 "}ul.lst-kix_785jj4szr34a-4{list-style-type:none}ul.lst-kix_hg7n0a8dlgvf-6{list-style-type:none}.lst-kix_pr131atimb8l-7>li:before{content:"\0025cb "}ul.lst-kix_785jj4szr34a-5{list-style-type:none}ul.lst-kix_hg7n0a8dlgvf-5{list-style-type:none}ul.lst-kix_785jj4szr34a-6{list-style-type:none}ul.lst-kix_hg7n0a8dlgvf-4{list-style-type:none}ul.lst-kix_785jj4szr34a-7{list-style-type:none}ul.lst-kix_hg7n0a8dlgvf-3{list-style-type:none}ul.lst-kix_785jj4szr34a-8{list-style-type:none}.lst-kix_pr131atimb8l-5>li:before{content:"\0025a0 "}ul.lst-kix_hg7n0a8dlgvf-8{list-style-type:none}.lst-kix_pr131atimb8l-4>li:before{content:"\0025cb "}.lst-kix_pr131atimb8l-8>li:before{content:"\0025a0 "}ul.lst-kix_hg7n0a8dlgvf-7{list-style-type:none}ol.lst-kix_n5z70wgxvefs-8.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-8 0}ul.lst-kix_785jj4szr34a-0{list-style-type:none}ul.lst-kix_785jj4szr34a-1{list-style-type:none}ul.lst-kix_785jj4szr34a-2{list-style-type:none}.lst-kix_pr131atimb8l-6>li:before{content:"\0025cf "}ul.lst-kix_785jj4szr34a-3{list-style-type:none}.lst-kix_n5z70wgxvefs-5>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-5}.lst-kix_qihahoz6j83w-8>li:before{content:"\0025a0 "}ol.lst-kix_n5z70wgxvefs-2.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-2 0}.lst-kix_qihahoz6j83w-7>li:before{content:"\0025cb "}.lst-kix_qihahoz6j83w-5>li:before{content:"\0025a0 "}ul.lst-kix_dpq1lef19uzo-8{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-6{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-5{list-style-type:none}.lst-kix_qihahoz6j83w-4>li:before{content:"\0025cb "}.lst-kix_qihahoz6j83w-6>li:before{content:"\0025cf "}ul.lst-kix_xh6dzfiz70hf-4{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-3{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-2{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-1{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-0{list-style-type:none}ul.lst-kix_dpq1lef19uzo-0{list-style-type:none}ul.lst-kix_dpq1lef19uzo-1{list-style-type:none}.lst-kix_qihahoz6j83w-2>li:before{content:"\0025a0 "}ul.lst-kix_dpq1lef19uzo-2{list-style-type:none}ul.lst-kix_dpq1lef19uzo-3{list-style-type:none}.lst-kix_qihahoz6j83w-3>li:before{content:"\0025cf "}ul.lst-kix_dpq1lef19uzo-4{list-style-type:none}ul.lst-kix_dpq1lef19uzo-5{list-style-type:none}ul.lst-kix_dpq1lef19uzo-6{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-8{list-style-type:none}ul.lst-kix_dpq1lef19uzo-7{list-style-type:none}ul.lst-kix_xh6dzfiz70hf-7{list-style-type:none}.lst-kix_n5z70wgxvefs-1>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-1}.lst-kix_qihahoz6j83w-1>li:before{content:"\0025cb "}.lst-kix_qihahoz6j83w-0>li:before{content:"\0025cf "}.lst-kix_pijsqepbbzpb-0>li:before{content:"\0025cf "}.lst-kix_1n620a6l6s3g-0>li:before{content:"\0025cf "}.lst-kix_dpq1lef19uzo-6>li:before{content:"\0025cf "}.lst-kix_dpq1lef19uzo-8>li:before{content:"\0025a0 "}.lst-kix_1n620a6l6s3g-1>li:before{content:"\0025cb "}.lst-kix_pijsqepbbzpb-1>li:before{content:"\0025cb "}.lst-kix_dpq1lef19uzo-5>li:before{content:"\0025a0 "}.lst-kix_n5z70wgxvefs-7>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-7}.lst-kix_pijsqepbbzpb-4>li:before{content:"\0025cb "}.lst-kix_1n620a6l6s3g-3>li:before{content:"\0025cf "}ol.lst-kix_n5z70wgxvefs-3.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-3 0}.lst-kix_1n620a6l6s3g-2>li:before{content:"\0025a0 "}.lst-kix_1n620a6l6s3g-4>li:before{content:"\0025cb "}.lst-kix_pijsqepbbzpb-2>li:before{content:"\0025a0 "}.lst-kix_pijsqepbbzpb-3>li:before{content:"\0025cf "}.lst-kix_dpq1lef19uzo-7>li:before{content:"\0025cb "}.lst-kix_pijsqepbbzpb-8>li:before{content:"\0025a0 "}.lst-kix_1n620a6l6s3g-7>li:before{content:"\0025cb "}.lst-kix_1n620a6l6s3g-6>li:before{content:"\0025cf "}.lst-kix_1n620a6l6s3g-8>li:before{content:"\0025a0 "}.lst-kix_dpq1lef19uzo-0>li:before{content:"\0025cf "}.lst-kix_1n620a6l6s3g-5>li:before{content:"\0025a0 "}.lst-kix_pijsqepbbzpb-5>li:before{content:"\0025a0 "}.lst-kix_dpq1lef19uzo-1>li:before{content:"\0025cb "}ul.lst-kix_g9bgj4bu2h0-0{list-style-type:none}ul.lst-kix_g9bgj4bu2h0-2{list-style-type:none}.lst-kix_dpq1lef19uzo-2>li:before{content:"\0025a0 "}.lst-kix_dpq1lef19uzo-4>li:before{content:"\0025cb "}ul.lst-kix_g9bgj4bu2h0-1{list-style-type:none}.lst-kix_pijsqepbbzpb-6>li:before{content:"\0025cf "}ul.lst-kix_hg7n0a8dlgvf-2{list-style-type:none}ul.lst-kix_hg7n0a8dlgvf-1{list-style-type:none}.lst-kix_pijsqepbbzpb-7>li:before{content:"\0025cb "}ul.lst-kix_hg7n0a8dlgvf-0{list-style-type:none}.lst-kix_dpq1lef19uzo-3>li:before{content:"\0025cf "}ul.lst-kix_g9bgj4bu2h0-8{list-style-type:none}ul.lst-kix_pijsqepbbzpb-7{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-7{list-style-type:none}ul.lst-kix_g9bgj4bu2h0-7{list-style-type:none}ul.lst-kix_pijsqepbbzpb-8{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-8{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-5{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-6{list-style-type:none}ul.lst-kix_1n620a6l6s3g-8{list-style-type:none}ul.lst-kix_g9bgj4bu2h0-4{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-3{list-style-type:none}ul.lst-kix_g9bgj4bu2h0-3{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-4{list-style-type:none}ul.lst-kix_g9bgj4bu2h0-6{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-1{list-style-type:none}ul.lst-kix_g9bgj4bu2h0-5{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-2{list-style-type:none}ul.lst-kix_1n620a6l6s3g-3{list-style-type:none}ul.lst-kix_pijsqepbbzpb-0{list-style-type:none}ul.lst-kix_qvcewxmuzrg7-0{list-style-type:none}ul.lst-kix_1n620a6l6s3g-2{list-style-type:none}ul.lst-kix_pijsqepbbzpb-1{list-style-type:none}ul.lst-kix_1n620a6l6s3g-1{list-style-type:none}ul.lst-kix_pijsqepbbzpb-2{list-style-type:none}ul.lst-kix_1n620a6l6s3g-0{list-style-type:none}ul.lst-kix_pijsqepbbzpb-3{list-style-type:none}ul.lst-kix_1n620a6l6s3g-7{list-style-type:none}ul.lst-kix_pijsqepbbzpb-4{list-style-type:none}ul.lst-kix_1n620a6l6s3g-6{list-style-type:none}ul.lst-kix_pijsqepbbzpb-5{list-style-type:none}ul.lst-kix_1n620a6l6s3g-5{list-style-type:none}ul.lst-kix_pijsqepbbzpb-6{list-style-type:none}ul.lst-kix_1n620a6l6s3g-4{list-style-type:none}ol.lst-kix_n5z70wgxvefs-1.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-1 0}.lst-kix_cp3k7292uvts-3>li:before{content:"\0025cf "}.lst-kix_cp3k7292uvts-7>li:before{content:"\0025cb "}.lst-kix_5bnah3qvhyc8-1>li:before{content:"\0025cb "}.lst-kix_cp3k7292uvts-1>li:before{content:"\0025cb "}.lst-kix_5bnah3qvhyc8-5>li:before{content:"\0025a0 "}.lst-kix_5bnah3qvhyc8-3>li:before{content:"\0025cf "}.lst-kix_cp3k7292uvts-5>li:before{content:"\0025a0 "}.lst-kix_as8tp5tsh1cy-1>li:before{content:"\0025cb "}.lst-kix_as8tp5tsh1cy-3>li:before{content:"\0025cf "}.lst-kix_as8tp5tsh1cy-7>li:before{content:"\0025cb "}.lst-kix_as8tp5tsh1cy-5>li:before{content:"\0025a0 "}.lst-kix_xh6dzfiz70hf-0>li:before{content:"\0025cf "}.lst-kix_n5z70wgxvefs-0>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-0}.lst-kix_xh6dzfiz70hf-2>li:before{content:"\0025a0 "}.lst-kix_g9bgj4bu2h0-6>li:before{content:"\0025cf "}.lst-kix_g9bgj4bu2h0-8>li:before{content:"\0025a0 "}ol.lst-kix_n5z70wgxvefs-0.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-0 0}.lst-kix_xh6dzfiz70hf-4>li:before{content:"\0025cb "}.lst-kix_3hjmgaf66qdz-0>li:before{content:"\0025cf "}.lst-kix_3hjmgaf66qdz-2>li:before{content:"\0025a0 "}.lst-kix_xh6dzfiz70hf-6>li:before{content:"\0025cf "}.lst-kix_xh6dzfiz70hf-8>li:before{content:"\0025a0 "}.lst-kix_3hjmgaf66qdz-6>li:before{content:"\0025cf "}.lst-kix_3hjmgaf66qdz-4>li:before{content:"\0025cb "}.lst-kix_3hjmgaf66qdz-8>li:before{content:"\0025a0 "}.lst-kix_n5z70wgxvefs-6>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-6}ul.lst-kix_qihahoz6j83w-3{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-6{list-style-type:none}ul.lst-kix_qihahoz6j83w-4{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-5{list-style-type:none}ul.lst-kix_qihahoz6j83w-5{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-4{list-style-type:none}ul.lst-kix_qihahoz6j83w-6{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-3{list-style-type:none}ul.lst-kix_qihahoz6j83w-7{list-style-type:none}ul.lst-kix_qihahoz6j83w-8{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-8{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-7{list-style-type:none}.lst-kix_5uzj2xa2gne-8>li:before{content:"\0025a0 "}ul.lst-kix_5bnah3qvhyc8-2{list-style-type:none}ul.lst-kix_qihahoz6j83w-0{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-1{list-style-type:none}ul.lst-kix_qihahoz6j83w-1{list-style-type:none}ul.lst-kix_5bnah3qvhyc8-0{list-style-type:none}ul.lst-kix_qihahoz6j83w-2{list-style-type:none}ol.lst-kix_n5z70wgxvefs-8{list-style-type:none}ol.lst-kix_n5z70wgxvefs-7{list-style-type:none}ol.lst-kix_n5z70wgxvefs-5.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-5 0}ol.lst-kix_n5z70wgxvefs-2{list-style-type:none}ol.lst-kix_n5z70wgxvefs-1{list-style-type:none}ol.lst-kix_n5z70wgxvefs-0{list-style-type:none}ol.lst-kix_n5z70wgxvefs-6{list-style-type:none}ol.lst-kix_n5z70wgxvefs-5{list-style-type:none}ol.lst-kix_n5z70wgxvefs-4{list-style-type:none}.lst-kix_n5z70wgxvefs-4>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-4}ol.lst-kix_n5z70wgxvefs-3{list-style-type:none}.lst-kix_qvcewxmuzrg7-5>li:before{content:"\0025a0 "}.lst-kix_qvcewxmuzrg7-6>li:before{content:"\0025cf "}.lst-kix_g9bgj4bu2h0-0>li:before{content:"\0025cf "}.lst-kix_qvcewxmuzrg7-4>li:before{content:"\0025cb "}.lst-kix_qvcewxmuzrg7-8>li:before{content:"\0025a0 "}.lst-kix_n5z70wgxvefs-2>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-2}.lst-kix_g9bgj4bu2h0-1>li:before{content:"\0025cb "}.lst-kix_qvcewxmuzrg7-1>li:before{content:"\0025cb "}.lst-kix_qvcewxmuzrg7-2>li:before{content:"\0025a0 "}.lst-kix_g9bgj4bu2h0-2>li:before{content:"\0025a0 "}.lst-kix_g9bgj4bu2h0-4>li:before{content:"\0025cb "}.lst-kix_5uzj2xa2gne-0>li:before{content:"\0025cf "}.lst-kix_qvcewxmuzrg7-3>li:before{content:"\0025cf "}.lst-kix_g9bgj4bu2h0-3>li:before{content:"\0025cf "}.lst-kix_5uzj2xa2gne-1>li:before{content:"\0025cb "}.lst-kix_5uzj2xa2gne-2>li:before{content:"\0025a0 "}.lst-kix_5uzj2xa2gne-4>li:before{content:"\0025cb "}.lst-kix_5uzj2xa2gne-3>li:before{content:"\0025cf "}.lst-kix_5uzj2xa2gne-7>li:before{content:"\0025cb "}ul.lst-kix_xdx87v22dufh-7{list-style-type:none}ul.lst-kix_xdx87v22dufh-8{list-style-type:none}.lst-kix_5uzj2xa2gne-6>li:before{content:"\0025cf "}ul.lst-kix_xdx87v22dufh-3{list-style-type:none}ul.lst-kix_xdx87v22dufh-4{list-style-type:none}.lst-kix_qvcewxmuzrg7-7>li:before{content:"\0025cb "}ul.lst-kix_xdx87v22dufh-5{list-style-type:none}ul.lst-kix_xdx87v22dufh-6{list-style-type:none}.lst-kix_5uzj2xa2gne-5>li:before{content:"\0025a0 "}.lst-kix_xdx87v22dufh-0>li:before{content:"\0025cf "}ul.lst-kix_xdx87v22dufh-0{list-style-type:none}.lst-kix_785jj4szr34a-0>li:before{content:"\0025cf "}.lst-kix_785jj4szr34a-1>li:before{content:"\0025cb "}ul.lst-kix_xdx87v22dufh-1{list-style-type:none}.lst-kix_n5z70wgxvefs-3>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-3,decimal) ". "}.lst-kix_n5z70wgxvefs-5>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-5,lower-roman) ". "}ul.lst-kix_xdx87v22dufh-2{list-style-type:none}.lst-kix_xdx87v22dufh-2>li:before{content:"\0025a0 "}.lst-kix_785jj4szr34a-3>li:before{content:"\0025cf "}.lst-kix_xdx87v22dufh-3>li:before{content:"\0025cf "}.lst-kix_n5z70wgxvefs-4>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-4,lower-latin) ". "}.lst-kix_n5z70wgxvefs-8>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-8,lower-roman) ". "}.lst-kix_xdx87v22dufh-4>li:before{content:"\0025cb "}.lst-kix_n5z70wgxvefs-1>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-1,lower-latin) ". "}.lst-kix_785jj4szr34a-2>li:before{content:"\0025a0 "}.lst-kix_xdx87v22dufh-5>li:before{content:"\0025a0 "}.lst-kix_n5z70wgxvefs-2>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-2,lower-roman) ". "}ul.lst-kix_3hjmgaf66qdz-7{list-style-type:none}ul.lst-kix_cp3k7292uvts-6{list-style-type:none}ul.lst-kix_3hjmgaf66qdz-6{list-style-type:none}ul.lst-kix_cp3k7292uvts-7{list-style-type:none}.lst-kix_785jj4szr34a-8>li:before{content:"\0025a0 "}ul.lst-kix_cp3k7292uvts-4{list-style-type:none}ul.lst-kix_3hjmgaf66qdz-8{list-style-type:none}ul.lst-kix_cp3k7292uvts-5{list-style-type:none}ul.lst-kix_cp3k7292uvts-2{list-style-type:none}.lst-kix_qvcewxmuzrg7-0>li:before{content:"\0025cf "}ul.lst-kix_cp3k7292uvts-3{list-style-type:none}.lst-kix_785jj4szr34a-7>li:before{content:"\0025cb "}ul.lst-kix_cp3k7292uvts-0{list-style-type:none}ul.lst-kix_cp3k7292uvts-1{list-style-type:none}.lst-kix_785jj4szr34a-4>li:before{content:"\0025cb "}.lst-kix_785jj4szr34a-5>li:before{content:"\0025a0 "}ul.lst-kix_3hjmgaf66qdz-1{list-style-type:none}ul.lst-kix_3hjmgaf66qdz-0{list-style-type:none}.lst-kix_n5z70wgxvefs-7>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-7,lower-latin) ". "}ul.lst-kix_3hjmgaf66qdz-3{list-style-type:none}ul.lst-kix_3hjmgaf66qdz-2{list-style-type:none}.lst-kix_785jj4szr34a-6>li:before{content:"\0025cf "}.lst-kix_5a1fzjqf1cfs-8>li:before{content:"\0025a0 "}ul.lst-kix_3hjmgaf66qdz-5{list-style-type:none}.lst-kix_xdx87v22dufh-1>li:before{content:"\0025cb "}ul.lst-kix_3hjmgaf66qdz-4{list-style-type:none}.lst-kix_n5z70wgxvefs-6>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-6,decimal) ". "}.lst-kix_5a1fzjqf1cfs-7>li:before{content:"\0025cb "}.lst-kix_5a1fzjqf1cfs-6>li:before{content:"\0025cf "}.lst-kix_hg7n0a8dlgvf-4>li:before{content:"\0025cb "}.lst-kix_hg7n0a8dlgvf-6>li:before{content:"\0025cf "}ul.lst-kix_as8tp5tsh1cy-8{list-style-type:none}.lst-kix_hg7n0a8dlgvf-1>li:before{content:"\0025cb "}.lst-kix_hg7n0a8dlgvf-5>li:before{content:"\0025a0 "}ul.lst-kix_as8tp5tsh1cy-5{list-style-type:none}.lst-kix_5a1fzjqf1cfs-3>li:before{content:"\0025cf "}ul.lst-kix_as8tp5tsh1cy-4{list-style-type:none}ul.lst-kix_as8tp5tsh1cy-7{list-style-type:none}.lst-kix_5a1fzjqf1cfs-4>li:before{content:"\0025cb "}.lst-kix_hg7n0a8dlgvf-0>li:before{content:"\0025cf "}.lst-kix_hg7n0a8dlgvf-8>li:before{content:"\0025a0 "}ul.lst-kix_as8tp5tsh1cy-6{list-style-type:none}ul.lst-kix_as8tp5tsh1cy-1{list-style-type:none}.lst-kix_5a1fzjqf1cfs-5>li:before{content:"\0025a0 "}.lst-kix_5bnah3qvhyc8-7>li:before{content:"\0025cb "}.lst-kix_5bnah3qvhyc8-8>li:before{content:"\0025a0 "}ul.lst-kix_as8tp5tsh1cy-0{list-style-type:none}ul.lst-kix_as8tp5tsh1cy-3{list-style-type:none}.lst-kix_hg7n0a8dlgvf-7>li:before{content:"\0025cb "}ul.lst-kix_as8tp5tsh1cy-2{list-style-type:none}.lst-kix_xdx87v22dufh-8>li:before{content:"\0025a0 "}ol.lst-kix_n5z70wgxvefs-4.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-4 0}.lst-kix_5a1fzjqf1cfs-0>li:before{content:"\0025cf "}.lst-kix_xdx87v22dufh-6>li:before{content:"\0025cf "}.lst-kix_xdx87v22dufh-7>li:before{content:"\0025cb "}.lst-kix_n5z70wgxvefs-0>li:before{content:"" counter(lst-ctn-kix_n5z70wgxvefs-0,decimal) ". "}.lst-kix_5a1fzjqf1cfs-2>li:before{content:"\0025a0 "}.lst-kix_hg7n0a8dlgvf-2>li:before{content:"\0025a0 "}.lst-kix_5a1fzjqf1cfs-1>li:before{content:"\0025cb "}.lst-kix_hg7n0a8dlgvf-3>li:before{content:"\0025cf "}.lst-kix_cp3k7292uvts-4>li:before{content:"\0025cb "}.lst-kix_cp3k7292uvts-0>li:before{content:"\0025cf "}.lst-kix_cp3k7292uvts-8>li:before{content:"\0025a0 "}.lst-kix_as8tp5tsh1cy-8>li:before{content:"\0025a0 "}.lst-kix_cp3k7292uvts-2>li:before{content:"\0025a0 "}.lst-kix_5bnah3qvhyc8-0>li:before{content:"\0025cf "}.lst-kix_5bnah3qvhyc8-6>li:before{content:"\0025cf "}.lst-kix_5bnah3qvhyc8-2>li:before{content:"\0025a0 "}.lst-kix_cp3k7292uvts-6>li:before{content:"\0025cf "}.lst-kix_5bnah3qvhyc8-4>li:before{content:"\0025cb "}.lst-kix_as8tp5tsh1cy-0>li:before{content:"\0025cf "}ul.lst-kix_cp3k7292uvts-8{list-style-type:none}.lst-kix_n5z70wgxvefs-8>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-8}ul.lst-kix_pr131atimb8l-4{list-style-type:none}ul.lst-kix_pr131atimb8l-3{list-style-type:none}ul.lst-kix_pr131atimb8l-6{list-style-type:none}ul.lst-kix_pr131atimb8l-5{list-style-type:none}.lst-kix_as8tp5tsh1cy-2>li:before{content:"\0025a0 "}.lst-kix_as8tp5tsh1cy-4>li:before{content:"\0025cb "}ul.lst-kix_pr131atimb8l-0{list-style-type:none}ul.lst-kix_pr131atimb8l-2{list-style-type:none}ul.lst-kix_pr131atimb8l-1{list-style-type:none}.lst-kix_as8tp5tsh1cy-6>li:before{content:"\0025cf "}ul.lst-kix_pr131atimb8l-8{list-style-type:none}ul.lst-kix_pr131atimb8l-7{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-3{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-2{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-1{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-0{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-8{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-7{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-6{list-style-type:none}ol.lst-kix_n5z70wgxvefs-6.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-6 0}ul.lst-kix_5a1fzjqf1cfs-5{list-style-type:none}ul.lst-kix_5a1fzjqf1cfs-4{list-style-type:none}.lst-kix_xh6dzfiz70hf-1>li:before{content:"\0025cb "}ul.lst-kix_5uzj2xa2gne-1{list-style-type:none}.lst-kix_g9bgj4bu2h0-5>li:before{content:"\0025a0 "}ul.lst-kix_5uzj2xa2gne-0{list-style-type:none}.lst-kix_xh6dzfiz70hf-5>li:before{content:"\0025a0 "}.lst-kix_xh6dzfiz70hf-3>li:before{content:"\0025cf "}.lst-kix_g9bgj4bu2h0-7>li:before{content:"\0025cb "}ol.lst-kix_n5z70wgxvefs-7.start{counter-reset:lst-ctn-kix_n5z70wgxvefs-7 0}ul.lst-kix_5uzj2xa2gne-3{list-style-type:none}ul.lst-kix_5uzj2xa2gne-2{list-style-type:none}ul.lst-kix_5uzj2xa2gne-5{list-style-type:none}ul.lst-kix_5uzj2xa2gne-4{list-style-type:none}ul.lst-kix_5uzj2xa2gne-7{list-style-type:none}.lst-kix_xh6dzfiz70hf-7>li:before{content:"\0025cb "}ul.lst-kix_5uzj2xa2gne-6{list-style-type:none}.lst-kix_3hjmgaf66qdz-1>li:before{content:"\0025cb "}ul.lst-kix_5uzj2xa2gne-8{list-style-type:none}.lst-kix_n5z70wgxvefs-3>li{counter-increment:lst-ctn-kix_n5z70wgxvefs-3}.lst-kix_3hjmgaf66qdz-3>li:before{content:"\0025cf "}.lst-kix_3hjmgaf66qdz-7>li:before{content:"\0025cb "}.lst-kix_3hjmgaf66qdz-5>li:before{content:"\0025a0 "}ol{margin:0;padding:0}table td,table th{padding:0}.c16{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}.c20{padding-top:20pt;padding-bottom:6pt;line-height:1.5;page-break-after:avoid;text-align:left}.c21{color:#595959;font-weight:400;font-size:14pt;font-family:"Arial"}.c13{font-size:10pt;font-family:Consolas,"Courier New";color:#3367d6;font-weight:400}.c11{padding-top:0pt;padding-bottom:16pt;line-height:1.5;text-align:left}.c0{font-size:10pt;font-family:Consolas,"Courier New";color:#000000;font-weight:400}.c6{font-size:10pt;font-family:Consolas,"Courier New";color:#9c27b0;font-weight:400}.c28{padding-top:0pt;padding-bottom:0pt;line-height:1.0;text-align:left}.c26{padding-top:20pt;padding-bottom:16pt;line-height:1.5;text-align:left}.c1{font-size:10pt;font-family:Consolas,"Courier New";color:#616161;font-weight:400}.c3{font-size:10pt;font-family:Consolas,"Courier New";color:#c53929;font-weight:400}.c5{border-spacing:0;border-collapse:collapse;margin-right:auto}.c8{color:#000000;font-weight:400;font-size:11pt;font-family:"Arial"}.c4{padding-top:0pt;padding-bottom:0pt;line-height:1.5;text-align:left}.c14{text-decoration-skip-ink:none;-webkit-text-decoration-skip:none;color:#1155cc;text-decoration:underline}.c7{color:#000000;font-weight:400;font-size:26pt;font-family:"Arial"}.c19{font-size:10pt;font-family:Consolas,"Courier New";color:#0f9d58;font-weight:400}.c27{color:#000000;font-weight:400;font-size:20pt;font-family:"Arial"}.c30{padding-top:0pt;padding-bottom:16pt;line-height:1.5;text-align:center}.c17{font-size:10pt;font-family:Consolas,"Courier New";color:#455a64;font-weight:400}.c25{padding-top:0pt;padding-bottom:3pt;line-height:1.5;text-align:left}.c31{background-color:#ffffff;max-width:468pt;padding:72pt 72pt 72pt 72pt}.c2{text-decoration:none;vertical-align:baseline;font-style:normal}.c22{-webkit-text-decoration-skip:none;text-decoration:underline;text-decoration-skip-ink:none}.c9{font-family:Consolas,"Courier New";color:#0d904f;font-weight:400}.c24{border:1px solid black;margin:5px}.c18{orphans:2;widows:2}.c12{color:inherit;text-decoration:inherit}.c15{height:11pt}.c10{height:0pt}.c23{page-break-after:avoid}.c29{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="c31"><div> <p class="c4 c18 c15"><span class="c8 c2"></span></p></div> <p class="c11"><span>Posted by Ned Williams</span><span>on</span><span class="c8 c2">, Project Zero</span></p> <p class="c11 c23 title" id="h.ndqbhr40lzdh"><span class="c7 c2">Introduction</span></p> <p class="c11"><span class="c8 c2">When I started my 20% project &ndash; an initiative where employees are allocated twenty-percent of their paid work time to pursue personal projects &ndash; &nbsp;with Project Zero, I wanted to see if I could apply the techniques I had learned fuzzing Chrome to XNU, the kernel used in iOS and macOS. My interest was sparked after learning some prominent members of the iOS research community believed the kernel was &ldquo;fuzzed to death,&rdquo; and my understanding was that most of the top researchers used auditing for vulnerability research. This meant finding new bugs with fuzzing would be meaningful in demonstrating the value of implementing newer fuzzing techniques. In this project, I pursued a somewhat unusual approach to fuzz XNU networking in userland by converting it into a library, &ldquo;booting&rdquo; it in userspace and using my standard fuzzing workflow to discover vulnerabilities. Somewhat surprisingly, this worked well enough to reproduce some of my peers&rsquo; recent discoveries and report some of my own, one of which was a reliable privilege escalation from the app context, CVE-2019-8605, dubbed &ldquo;SockPuppet.&rdquo; I&rsquo;m excited to open source this fuzzing project, &ldquo;sockfuzzer,&rdquo; for the community to learn from and adapt. In this post, we&rsquo;ll do a deep dive into its design and implementation.</span></p> <p class="c11 c23 title" id="h.hjehdh7g62jx"><span class="c7 c2">Attack Surface Review and Target Planning</span></p><h1 class="c23 c26" id="h.3g484yfwyzbz"><span class="c27 c2">Choosing Networking</span></h1> <p class="c11"><span>We&rsquo;re at the beginning of a multistage</span><span>&nbsp;pr</span><span>oject. I had enormous respect for the difficulty of the task ahead of me. I knew I would need to be careful investing time at each stage of the process, constantly looking for evidence that I needed to change direction. The first big decision was to decide what exactly we </span><span class="c29">wanted</span><span class="c8 c2">&nbsp;to target.</span></p> <p class="c11"><span>I started by downloading the </span><span class="c14"><a class="c121" href="https://opensource.apple.com/tarballs/xnu/">XNU sources</a></span><span class="c8 c2">&nbsp;and reviewing them, looking for areas that handled a lot of attacker-controlled input and seemed amenable to fuzzing &ndash; immediately the networking subsystem jumped out as worthy of research. I had just exploited a Chrome sandbox bug that leveraged collaboration between an exploited renderer process and a server working in concert. I recognized these attack surfaces&rsquo; power, where some security-critical code is &ldquo;sandwiched&rdquo; between two attacker-controlled entities. The Chrome browser process is prone to use after free vulnerabilities due to the difficulty of managing state for large APIs, and I suspected XNU would have the same issue. Networking features both parsing and state management. I figured that even if others had already fuzzed the parsers extensively, there could still be use after free vulnerabilities lying dormant.</span></p> <p class="c11"><span>I then proceeded to look at recent bug reports. Two bugs that caught my eye: the </span><span class="c14"><a class="c121" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1558">mptcp overflow</a></span><span>&nbsp;discovered by Ian Beer and the ICMP </span><span class="c14"><a class="c121" href="https://securitylab.github.com/research/apple-xnu-icmp-error-CVE-2018-4407">out of bounds write</a></span><span class="c8 c2">&nbsp;found by Kevin Backhouse. Both of these are somewhat &ldquo;straightforward&rdquo; buffer overflows. The bugs&rsquo; simplicity hinted that kernel networking, even packet parsing, was sufficiently undertested. A fuzzer combining network syscalls and arbitrary remote packets should be large enough in scope to reproduce these issues and find new ones.</span></p> <p class="c11"><span class="c8 c2">Digging deeper, I wanted to understand how to reach these bugs in practice. By cross-referencing the functions and setting kernel breakpoints in a VM, I managed to get a more concrete idea. Here&rsquo;s the call stack for Ian&rsquo;s MPTCP bug:</span></p> <p class="c11"></p> <p class="c11"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixaqhrlPJxgqVridccvdElpi6yxaoJCSUXDp5q8hm_F66e5WHW3NRaFwmy-OWQvCKz661k3LEfi4A4r2sa1LkgMb8pu8CEVjKbzTkblc8SZZYcOsKkw7u0uG2qo5KzCdjbxixJ-CplQI2nohuVE1_t07PiNW-xRxnW-3e4WtILcCE6CoYjbN1D6UPi/s623/image3%282%29.png" style="display: block; padding: 1em 0;text-align: center;"><img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixaqhrlPJxgqVridccvdElpi6yxaoJCSUXDp5q8hm_F66e5WHW3NRaFwmy-OWQvCKz661k3LEfi4A4r2sa1LkgMb8pu8CEVjKbzTkblc8SZZYcOsKkw7u0uG2qo5KzCdjbxixJ-CplQI2nohuVE1_t07PiNW-xRxnW-3e4WtILcCE6CoYjbN1D6UPi/s623/image3%282%29.png" style="max-height: 750; max-width: 600px;" /></a></span></p> <p class="c11"><span>The buggy function in question is </span><span class="c9">mptcp_usr_connectx</span><span>. Moving up the call stack, we find the </span><span class="c9">connectx</span><span>&nbsp;syscall, which we see in Ian&rsquo;s original testcase. If we were to write a fuzzer to find this bug, how would we do it? Ultimately, whatever we do has to both find the bug and give us the information we need to reproduce it on the real kernel. Calling </span><span class="c9">mptcp_usr_connectx</span><span>&nbsp;directly should surely find the bug, but this seems like the wrong idea because it takes a lot of arguments. Modeling a fuzzer well enough to call this function directly in a way representative of the real code is no easier than auditing the code in the first place, so we&rsquo;ve not made things any easier by writing a targeted fuzzer. It&rsquo;s also wasted effort to write a target for each function this small. On the other hand, the further up the call stack we go, the more complexity we may have to support and the less chance we have of landing on the bug. If I were trying to unit test the networking stack, I would probably avoid the syscall layer and call the intermediate helper functions as a middle ground. This is exactly what I tried in the first draft of the fuzzer; I used </span><span class="c14"><a class="c121" href="https://developer.apple.com/documentation/kernel/1396122-sock_socket">sock_socket</a></span><span>&nbsp;to create </span><span class="c9">struct socket*</span><span>&nbsp;objects to pass to </span><span class="c9">connectitx</span><span>&nbsp;in the hopes that it would be easy to reproduce this bug while being high-enough level that this bug could plausibly have been discovered without knowing where to look for it</span><span>. Surprisingly, after some experimentation, it turned out to be easier to simply call the syscalls directly (via </span><span class="c9">connectx</span><span class="c8 c2">). This makes it easier to translate crashing inputs into programs to run against a real kernel since testcases map 1:1 to syscalls. We&rsquo;ll see more details about this later.</span></p> <p class="c11"><span>We can&rsquo;t test networking properly without accounting for packets. In this case, data comes from the hardware, not via syscalls from a user process. We&rsquo;ll have to expose this functionality to our fuzzer. To figure out how to extend our framework to support random packet delivery, we can use our next example bug. Let&rsquo;s take a look at the call stack for delivering a packet to trigger the ICMP bug reported by Kevin Backhouse:</span></p> <p class="c30"></p> <p class="c11"><span class="c8 c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN_4qMCDG0R3Ix94ctakWAgk3QmZ1JVD0IxQVjr9ft44Eu2a3VYxzWkueZJvf8MUd2qsf2Z-Qk2elUh_Zl-Cx5D9k6ueDM-pJNT9LeT3Ruhtc_CAgn0SL1M2XVCL_BYiTya834YqPEYuU5kH0nU68d7eUJrsUuY-hGEZ3EfiX_yCZ7ZvlDnQoQceOe/s450/image2%281%29.png" style="display: block; padding: 1em 0;text-align: center;"><img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjN_4qMCDG0R3Ix94ctakWAgk3QmZ1JVD0IxQVjr9ft44Eu2a3VYxzWkueZJvf8MUd2qsf2Z-Qk2elUh_Zl-Cx5D9k6ueDM-pJNT9LeT3Ruhtc_CAgn0SL1M2XVCL_BYiTya834YqPEYuU5kH0nU68d7eUJrsUuY-hGEZ3EfiX_yCZ7ZvlDnQoQceOe/s450/image2%281%29.png" style="max-height: 750px; max-width: 600px;" /></a></span></p> <p class="c11"><span>To reach the buggy function, </span><span class="c9">icmp_error</span><span>, the call stack is deeper, and unlike with syscalls, it&rsquo;s not immediately obvious which of these functions we should call to cover the relevant code. Starting from the very top of the call stack, we see that the crash occurred in a kernel thread running the </span><span class="c9">dlil_input_thread_func</span><span>&nbsp;function. DLIL stands for Data Link Interface Layer, a reference to the OSI model&rsquo;s </span><span class="c14"><a class="c121" href="https://en.wikipedia.org/wiki/Data_link_layer">data link layer</a></span><span>. Moving further down the stack, we see </span><span class="c9">ether_inet_input</span><span>, indicating an Ethernet packet (since I tested this issue using Ethernet). We finally make it down to the IP layer, where </span><span class="c9">ip_dooptions</span><span>&nbsp;signals an </span><span class="c9">icmp_error</span><span>. As an attacker, we probably don&rsquo;t have a lot of control over the interface a user uses to receive our input, so we can rule out some of the </span><span>uppermost layers</span><span>. We also don&rsquo;t want to deal with threads in our fuzzer, another design tradeoff we&rsquo;ll describe in more detail later. </span><span class="c9">proto_input</span><span>&nbsp;and </span><span class="c9">ip_proto_input</span><span>&nbsp;don&rsquo;t do much, so I decided that </span><span class="c9">ip_proto</span><span>&nbsp;was where I would inject packets, simply by calling the function when I wanted to deliver a packet. After reviewing </span><span class="c9">proto_register_input</span><span>, I discovered another function called </span><span class="c9">ip6_input</span><span>, which was the entry point for the IPv6 code. Here&rsquo;s the prototype for </span><span class="c9">ip_input</span><span class="c8 c2">:</span></p><a id="t.cf5c301b37182659cde971ba454e9537e2d2f75a"></a><a id="t.0"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">void</span><span class="c0">&nbsp;ip_input</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;mbuf </span><span class="c1">*</span><span class="c0">m</span><span class="c1">);</span></p></td></tr></tbody></table> <p class="c11"><span><br>Mbufs are message buffers, a standard buffer format used in network stacks. They enable multiple small packets to be chained together through a linked list. So we just need to generate mbufs with random data before calling </span><span class="c9">ip_input</span><span class="c8 c2">.</span></p> <p class="c11"><span class="c8 c2">I was surprised by how easy it was to work with the network stack compared to the syscall interface. `ip_input` and `ip6_input` pure functions that don&rsquo;t require us to know any state to call them. But stepping back, it made more sense. Packet delivery is inherently a clean interface: our kernel has no idea what arbitrary packets may be coming in, so the interface takes a raw packet and then further down in the stack decides how to handle it. Many packets contain metadata that affect the kernel state once received. For example, TCP or UDP packets will be matched to an existing connection by their port number.</span></p> <p class="c11"><span>Most modern coverage guided fuzzers, including this LibFuzzer-based project, use a design inspired by AFL. When a test case with some known coverage is mutated and the mutant produces coverage that hasn&rsquo;t been seen before, the mutant is added to the current corpus of inputs. It becomes available for further mutations to produce even deeper coverage. Lcamtuf, the author of AFL, has an excellent demonstration of how this algorithm </span><span class="c14"><a class="c121" href="https://lcamtuf.blogspot.com/2014/11/pulling-jpegs-out-of-thin-air.html">created JPEGs using coverage feedback</a></span><span>&nbsp;with no well-formed starting samples. In essence, most poorly-formed inputs are rejected early. When a mutated input passes a validation check, the input is saved. Then that input can be mutated until it manages to pass the second validation check, and so on. This </span><span>hill climbing algorithm</span><span>&nbsp;has no problem generating dependent sequences of API calls, in this case to interleave syscalls with </span><span class="c9">ip_input</span><span>&nbsp;and </span><span class="c9">ip6_input</span><span>. Random syscalls can get the kernel into some state where it&rsquo;s expecting a packet. Later, when libFuzzer guesses a packet that gets the kernel into some new state, the hill climbing algorithm will record a new test case when it sees new coverage. Dependent sequences of syscalls and packets are brute-forced in a linear fashion, one call at a time.</span></p> <p class="c11 c23 title" id="h.eby3d6n6dnx2"><span class="c7 c2">Designing for (Development) Speed</span></p> <p class="c11"><span class="c8 c2">Now that we know where to attack this code base, it&rsquo;s a matter of building out the fuzzing research platform. I like thinking of it this way because it emphasizes that this fuzzer is a powerful assistant to a researcher, but it can&rsquo;t do all the work. Like any other test framework, it empowers the researcher to make hypotheses and run experiments over code that looks buggy. For the platform to be helpful, it needs to be comfortable and fun to work with and get out of the way.</span></p> <p class="c11"><span class="c8 c2">When it comes to standard practice for kernel fuzzing, there&rsquo;s a pretty simple spectrum for strategies. On one end, you fuzz self-contained functions that are security-critical, e.g., OSUnserializeBinary. These are easy to write and manage and are generally quite performant. On the other end, you have &ldquo;end to end&rdquo; kernel testing that performs random syscalls against a real kernel instance. These heavyweight fuzzers have the advantage of producing issues that you know are actionable right away, but setup and iterative development are slower. I wanted to try a hybrid approach that could preserve some of the benefits of each style. To do so, I would port the networking stack of XNU out of the kernel and into userland while preserving as much of the original code as possible. Kernel code can be surprisingly portable and amenable to unit testing, even when run outside its natural environment.</span></p> <p class="c11"><span>There has been a push to add more user-mode unit testing to Linux. If you look at the documentation for Linux&rsquo;s </span><span class="c14"><a class="c121" href="https://www.kernel.org/doc/html/latest/dev-tools/kunit/index.html">KUnit project</a></span><span class="c8 c2">, there&rsquo;s an excellent quote from Linus Torvalds: &ldquo;&hellip; a lot of people seem to think that performance is about doing the same thing, just doing it faster, and that is not true. That is not what performance is all about. If you can do something really fast, really well, people will start using it differently.&rdquo; This statement echoes the experience I had writing targeted fuzzers for code in Chrome&rsquo;s browser process. Due to extensive unit testing, Chrome code is already well-factored for fuzzing. In a day&rsquo;s work, I could try out many iterations of a fuzz target and the edit/build/run cycle. I didn&rsquo;t have a similar mechanism out of the box with XNU. In order to perform a unit test, I would need to rebuild the kernel. And despite XNU being considerably smaller than Chrome, incremental builds were slower due to the older kmk build system. I wanted to try bridging this gap for XNU.</span></p> <p class="c11 c23 title" id="h.9elbs1tajoqo"><span>Setting up the Scaffolding</span></p> <p class="c11"><span>&ldquo;Unit&rdquo; testing a kernel up through the syscall layer sounds like a big task, but it&rsquo;s easier than you&rsquo;d expect if you forgo some complexity. </span><span>We&rsquo;ll start by building all of the individual kernel</span><span class="c8 c2">&nbsp;object files from source using the original build flags. But instead of linking everything together to produce the final kernel binary, we link in only the subset of objects containing code in our target attack surface. We then stub or fake the rest of the functionality. Thanks to the recon in the previous section, we already know which functions we want to call from our fuzzer. I used that information to prepare a minimal list of source objects to include in our userland port.</span></p> <p class="c11"><span>Before we dive in, let&rsquo;s define the overall structure of the project as pictured below. There&rsquo;s going to be a fuzz target implemented in C++ that translates fuzzed inputs into interactions with the userland XNU library. The target code, </span><span class="c9">libxnu</span><span>, exposes a few wrapper symbols for syscalls and </span><span class="c9">ip_input</span><span>&nbsp;as mentioned in the attack surface review section. The fuzz target also exposes its random sequence of bytes to kernel APIs such as </span><span class="c9">copyin</span><span>&nbsp;or </span><span class="c9">copyout</span><span class="c8 c2">, whose implementations have been replaced with fakes that use fuzzed input data.</span></p> <p class="c11"></p> <p class="c11"><span class="c8 c2"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd7HxZOpEaZ0zOKXMwVP0f3hRjwuUrChoR3_v_y91gddRnq4T-t7FCJt5mmG3EGwaK3-HT_hibQyi-0CgwigF9hGZBfNaJhssUQG0KBYoyVGpXRHWgtVAUhC1EOgHgyb_vfiqdYGWxZE7N9y0ysw-0ikT-Kj_ljONiFGGMUPagiidn4dzLgSP8EvX-/s1051/image1%283%29.png" style="display: block; padding: 1em 0;text-align: center;"><img alt="" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhd7HxZOpEaZ0zOKXMwVP0f3hRjwuUrChoR3_v_y91gddRnq4T-t7FCJt5mmG3EGwaK3-HT_hibQyi-0CgwigF9hGZBfNaJhssUQG0KBYoyVGpXRHWgtVAUhC1EOgHgyb_vfiqdYGWxZE7N9y0ysw-0ikT-Kj_ljONiFGGMUPagiidn4dzLgSP8EvX-/s1051/image1%283%29.png" style="max-height: 750; max-width: 600px;" /></a></span></p> <p class="c11"><span class="c8 c2">To make development more manageable, I decided to create a new build system using CMake, as it supported Ninja for fast rebuilds. One drawback here is the original build system has to be run every time upstream is updated to deal with generated sources, but this is worth it to get a faster development loop. I captured all of the compiler invocations during a normal kernel build and used those to reconstruct the flags passed to build the various kernel subsystems. Here&rsquo;s what that first pass looks like:</span></p><a id="t.509a56bc4ddc72babc39c522f6fca5af9dbff3f9"></a><a id="t.1"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">project</span><span class="c1">(</span><span class="c0">libxnu</span><span class="c1">)</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">set</span><span class="c1">(</span><span class="c0 c2">XNU_DEFINES</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">-</span><span class="c0 c2">DAPPLE</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">-</span><span class="c0 c2">DKERNEL</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17"># ...</span></p> <p class="c4"><span class="c1">)</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">set</span><span class="c1">(</span><span class="c0 c2">XNU_SOURCES</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; bsd</span><span class="c1">/</span><span class="c0">conf</span><span class="c1">/</span><span class="c0">param</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; bsd</span><span class="c1">/</span><span class="c0">kern</span><span class="c1">/</span><span class="c0">kern_asl</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; bsd</span><span class="c1">/</span><span class="c0">net</span><span class="c1">/</span><span class="c6">if</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; bsd</span><span class="c1">/</span><span class="c0">netinet</span><span class="c1">/</span><span class="c0">ip_input</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17"># ...</span></p> <p class="c4"><span class="c1">)</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">add_library</span><span class="c1">(</span><span class="c0">xnu SHARED $</span><span class="c1">{</span><span class="c0">XNU_SOURCES</span><span class="c1">}</span><span class="c0">&nbsp;$</span><span class="c1">{</span><span class="c0">FUZZER_FILES</span><span class="c1">}</span><span class="c0">&nbsp;$</span><span class="c1">{</span><span class="c0">XNU_HEADERS</span><span class="c1">})</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">protobuf_generate_cpp</span><span class="c1">(</span><span class="c0">NET_PROTO_SRCS NET_PROTO_HDRS fuzz</span><span class="c1">/</span><span class="c0">net_fuzzer</span><span class="c1">.</span><span class="c0">proto</span><span class="c1">)</span></p> <p class="c4"><span class="c0">add_executable</span><span class="c1">(</span><span class="c0">net_fuzzer fuzz</span><span class="c1">/</span><span class="c0">net_fuzzer</span><span class="c1">.</span><span class="c0">cc $</span><span class="c1">{</span><span class="c0">NET_PROTO_SRCS</span><span class="c1">}</span><span class="c0">&nbsp;$</span><span class="c1">{</span><span class="c0">NET_PROTO_HDRS</span><span class="c1">})</span></p> <p class="c4"><span class="c0">target_include_directories</span><span class="c1">(</span><span class="c0">net_fuzzer PRIVATE libprotobuf</span><span class="c1">-</span><span class="c0">mutator</span><span class="c1">)</span></p> <p class="c4"><span class="c0">target_compile_options</span><span class="c1">(</span><span class="c0">net_fuzzer PRIVATE $</span><span class="c1">{</span><span class="c0">FUZZER_CXX_FLAGS</span><span class="c1">})</span></p></td></tr></tbody></table> <p class="c11"><span><br>Of course, without the rest of the kernel, we see tons of missing symbols.</span></p><a id="t.c5de84d30da6bb237fe5cdc6ee881ad5d422b21a"></a><a id="t.2"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">&nbsp; </span><span class="c19">&quot;_zdestroy&quot;</span><span class="c1">,</span><span class="c0">&nbsp;referenced </span><span class="c6">from</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _if_clone_detach </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c6">if</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c19">&quot;_zfree&quot;</span><span class="c1">,</span><span class="c0">&nbsp;referenced </span><span class="c6">from</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _kqueue_destroy </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _knote_free </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _kqworkloop_get_or_create </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _kev_delete </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _pipepair_alloc </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">sys_pipe</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _pipepair_destroy_pipe </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">sys_pipe</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _so_cache_timer </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">uipc_socket</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">...</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c19">&quot;_zinit&quot;</span><span class="c1">,</span><span class="c0">&nbsp;referenced </span><span class="c6">from</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _knote_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _kern_event_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _pipeinit </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">sys_pipe</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _socketinit </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">uipc_socket</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _unp_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">uipc_usrreq</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _cfil_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">content_filter</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _tcp_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">tcp_subr</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">...</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c19">&quot;_zone_change&quot;</span><span class="c1">,</span><span class="c0">&nbsp;referenced </span><span class="c6">from</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _knote_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _kern_event_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">kern_event</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _socketinit </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">uipc_socket</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _cfil_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">content_filter</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _tcp_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c0">tcp_subr</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _ifa_init </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c6">if</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; _if_clone_attach </span><span class="c6">in</span><span class="c0">&nbsp;libxnu</span><span class="c1">.</span><span class="c0">a</span><span class="c1">(</span><span class="c6">if</span><span class="c1">.</span><span class="c0">c</span><span class="c1">.</span><span class="c0">o</span><span class="c1">)</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">...</span></p> <p class="c4"><span class="c0">ld</span><span class="c1">:</span><span class="c0">&nbsp;symbol</span><span class="c1">(</span><span class="c0">s</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c6">not</span><span class="c0">&nbsp;found </span><span class="c6">for</span><span class="c0 c2">&nbsp;architecture x86_64</span></p> <p class="c4"><span class="c0">clang</span><span class="c1">:</span><span class="c0">&nbsp;error</span><span class="c1">:</span><span class="c0">&nbsp;linker command failed </span><span class="c6">with</span><span class="c0">&nbsp;</span><span class="c6">exit</span><span class="c0">&nbsp;code </span><span class="c3">1</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">use</span><span class="c0">&nbsp;</span><span class="c1">-</span><span class="c0">v to see invocation</span><span class="c1">)</span></p> <p class="c4"><span class="c0">ninja</span><span class="c1">:</span><span class="c0">&nbsp;build stopped</span><span class="c1">:</span><span class="c0">&nbsp;subcommand failed</span><span class="c1">.</span></p></td></tr></tbody></table> <p class="c11"><span><br>To get our initial targeted fuzzer working, we can do a simple trick by linking against a file containing stubbed implementations of all of these. We take advantage of C&rsquo;s weak type system here. For each function we need to implement, we can link an implementation </span><span class="c9">void func() { assert(false); }</span><span>. The arguments passed to the function are simply ignored, and a crash will occur whenever the target code attempts to call it. This goal can be achieved with linker flags, but it was a simple enough solution that allowed me to get nice backtraces when I hit an unimplemented function.</span></p><a id="t.b8228357b6d205653ae1179c620e72df885cb433"></a><a id="t.3"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c17">// Unimplemented stub functions</span></p> <p class="c4"><span class="c17">// These should be replaced with real or mock impls.</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c17">#include</span><span class="c0">&nbsp;</span><span class="c19">&lt;kern/assert.h&gt;</span></p> <p class="c4"><span class="c17">#include</span><span class="c0">&nbsp;</span><span class="c19">&lt;stdbool.h&gt;</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">int</span><span class="c0">&nbsp;printf</span><span class="c1">(</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c6">char</span><span class="c1">*</span><span class="c0">&nbsp;format</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c1">...);</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">void</span><span class="c0">&nbsp;</span><span class="c13">Assert</span><span class="c1">(</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c6">char</span><span class="c1">*</span><span class="c0">&nbsp;file</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">int</span><span class="c0">&nbsp;line</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c6">char</span><span class="c1">*</span><span class="c0">&nbsp;expression</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; printf</span><span class="c1">(</span><span class="c19">&quot;%s: assert failed on line %d: %s\n&quot;</span><span class="c1">,</span><span class="c0">&nbsp;file</span><span class="c1">,</span><span class="c0">&nbsp;line</span><span class="c1">,</span><span class="c0">&nbsp;expression</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; __builtin_trap</span><span class="c1">();</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">void</span><span class="c0">&nbsp;</span><span class="c13">IOBSDGetPlatformUUID</span><span class="c1">()</span><span class="c0">&nbsp;</span><span class="c1">{</span><span class="c0">&nbsp;</span><span class="c6">assert</span><span class="c1">(</span><span class="c6">false</span><span class="c1">);</span><span class="c0">&nbsp;</span><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">void</span><span class="c0">&nbsp;</span><span class="c13">IOMapperInsertPage</span><span class="c1">()</span><span class="c0">&nbsp;</span><span class="c1">{</span><span class="c0">&nbsp;</span><span class="c6">assert</span><span class="c1">(</span><span class="c6">false</span><span class="c1">);</span><span class="c0">&nbsp;</span><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c17">// ...</span></p></td></tr></tbody></table> <p class="c11"><span class="c8 c2"><br>Then we just link this file into the XNU library we&rsquo;re building by adding it to the source list:</span></p><a id="t.534c83683172ba6897a00c87407d33404b429f6e"></a><a id="t.4"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">set</span><span class="c1">(</span><span class="c0 c2">XNU_SOURCES</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; bsd</span><span class="c1">/</span><span class="c0">conf</span><span class="c1">/</span><span class="c0">param</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; bsd</span><span class="c1">/</span><span class="c0">kern</span><span class="c1">/</span><span class="c0">kern_asl</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17"># ...</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; fuzz</span><span class="c1">/</span><span class="c0">syscall_wrappers</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; fuzz</span><span class="c1">/</span><span class="c0">ioctl</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; fuzz</span><span class="c1">/</span><span class="c0">backend</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; fuzz</span><span class="c1">/</span><span class="c0">stubs</span><span class="c1">.</span><span class="c0 c2">c</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; fuzz</span><span class="c1">/</span><span class="c0">fake_impls</span><span class="c1">.</span><span class="c0">c</span></p></td></tr></tbody></table> <p class="c11"><span><br>As you can see, there are some other files I included in the XNU library that represent faked implementations and helper code to expose some internal kernel APIs. To make sure our fuzz target will call code in the linked library, and not some other host functions (syscalls) with a clashing name, we hide all of the symbols in </span><span class="c9">libxnu</span><span>&nbsp;by default and then expose a set of wrappers that call those functions on our behalf. I hide all the names by default using a CMake setting </span><span class="c9">set_target_properties(xnu PROPERTIES C_VISIBILITY_PRESET hidden)</span><span class="c8 c2">. Then we can link in a file (fuzz/syscall_wrappers.c) containing wrappers like the following:</span></p><a id="t.e0503b6026972fa7d7dd9fa845e61836b2ed21ca"></a><a id="t.5"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">__attribute__</span><span class="c1">((</span><span class="c0">visibility</span><span class="c1">(</span><span class="c19">&quot;default&quot;</span><span class="c1">)))</span><span class="c0">&nbsp;</span><span class="c6">int</span><span class="c0">&nbsp;accept_wrapper</span><span class="c1">(</span><span class="c6">int</span><span class="c0">&nbsp;s</span><span class="c1">,</span><span class="c0">&nbsp;caddr_t name</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; socklen_t</span><span class="c1">*</span><span class="c0">&nbsp;anamelen</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">int</span><span class="c1">*</span><span class="c0">&nbsp;retval</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;accept_args uap </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">s </span><span class="c1">=</span><span class="c0">&nbsp;s</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">name </span><span class="c1">=</span><span class="c0">&nbsp;name</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">anamelen </span><span class="c1">=</span><span class="c0">&nbsp;anamelen</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">};</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;accept</span><span class="c1">(</span><span class="c0">kernproc</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">uap</span><span class="c1">,</span><span class="c0">&nbsp;retval</span><span class="c1">);</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>Note the visibility attribute that explicitly exports the symbol from the library. Due to the simplicity of these wrappers I created a script to automate this called generate_fuzzer.py using </span><span class="c9">syscalls.master</span><span class="c8 c2">.<br></span></p> <p class="c11"><span class="c8 c2">With the stubs in place, we can start writing a fuzz target now and come back to deal with implementing them later. We will see a crash every time the target code attempts to use one of the functions we initially left out. Then we get to decide to either include the real implementation (and perhaps recursively require even more stubbed function implementations) or to fake the functionality.</span></p> <p class="c11"><span>A bonus of getting a build working with CMake was to create multiple targets with different instrumentation. Doing so allows me to generate coverage reports using clang-coverage:</span></p><a id="t.e3e5dbef0102c66c9a42aebd0535293cd5f2fcba"></a><a id="t.6"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">target_compile_options</span><span class="c1">(</span><span class="c0">xnu</span><span class="c1">-</span><span class="c0">cov PRIVATE $</span><span class="c1">{</span><span class="c0">XNU_C_FLAGS</span><span class="c1">}</span><span class="c0">&nbsp;</span><span class="c1">-</span><span class="c0">DLIBXNU_BUILD</span><span class="c1">=</span><span class="c3">1</span><span class="c0">&nbsp;</span><span class="c1">-</span><span class="c0">D_FORTIFY_SOURCE</span><span class="c1">=</span><span class="c3">0</span><span class="c0">&nbsp;</span><span class="c1">-</span><span class="c0">fprofile</span><span class="c1">-</span><span class="c0">instr</span><span class="c1">-</span><span class="c0">generate </span><span class="c1">-</span><span class="c0">fcoverage</span><span class="c1">-</span><span class="c0">mapping</span><span class="c1 c2">)</span></p></td></tr></tbody></table> <p class="c11"><span class="c8 c2"><br>With that, we just add a fuzz target file and a protobuf file to use with protobuf-mutator and we&rsquo;re ready to get started:</span></p><a id="t.94984d9cd1732c1405481ef4bebbc7ba7e4bcac5"></a><a id="t.7"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">protobuf_generate_cpp</span><span class="c1">(</span><span class="c0">NET_PROTO_SRCS NET_PROTO_HDRS fuzz</span><span class="c1">/</span><span class="c0">net_fuzzer</span><span class="c1">.</span><span class="c0">proto</span><span class="c1">)</span></p> <p class="c4"><span class="c0">add_executable</span><span class="c1">(</span><span class="c0">net_fuzzer fuzz</span><span class="c1">/</span><span class="c0">net_fuzzer</span><span class="c1">.</span><span class="c0">cc $</span><span class="c1">{</span><span class="c0">NET_PROTO_SRCS</span><span class="c1">}</span><span class="c0">&nbsp;$</span><span class="c1">{</span><span class="c0">NET_PROTO_HDRS</span><span class="c1">})</span></p> <p class="c4"><span class="c0">target_include_directories</span><span class="c1">(</span><span class="c0">net_fuzzer PRIVATE libprotobuf</span><span class="c1">-</span><span class="c0">mutator</span><span class="c1">)</span></p> <p class="c4"><span class="c0">target_compile_options</span><span class="c1">(</span><span class="c0 c2">net_fuzzer</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;PRIVATE </span><span class="c1">-</span><span class="c0 c2">g</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c1">-</span><span class="c0">std</span><span class="c1">=</span><span class="c0">c</span><span class="c1">++</span><span class="c3">11</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c1">-</span><span class="c13">Werror</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c1">-</span><span class="c13">Wno</span><span class="c1">-</span><span class="c0">address</span><span class="c1">-</span><span class="c0">of</span><span class="c1">-</span><span class="c0">packed</span><span class="c1">-</span><span class="c0 c2">member</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;$</span><span class="c1">{</span><span class="c0">FUZZER_CXX_FLAGS</span><span class="c1">})</span></p> <p class="c4"><span class="c6">if</span><span class="c1">(</span><span class="c0">APPLE</span><span class="c1">)</span></p> <p class="c4"><span class="c0">target_link_libraries</span><span class="c1">(</span><span class="c0">net_fuzzer $</span><span class="c1">{</span><span class="c0">FUZZER_LD_FLAGS</span><span class="c1">}</span><span class="c0">&nbsp;xnu fuzzer protobuf</span><span class="c1">-</span><span class="c0">mutator $</span><span class="c1">{</span><span class="c13">Protobuf_LIBRARIES</span><span class="c1">})</span></p> <p class="c4"><span class="c6">else</span><span class="c1">()</span></p> <p class="c4"><span class="c0">target_link_libraries</span><span class="c1">(</span><span class="c0">net_fuzzer $</span><span class="c1">{</span><span class="c0">FUZZER_LD_FLAGS</span><span class="c1">}</span><span class="c0">&nbsp;xnu fuzzer protobuf</span><span class="c1">-</span><span class="c0">mutator $</span><span class="c1">{</span><span class="c13">Protobuf_LIBRARIES</span><span class="c1">}</span><span class="c0">&nbsp;pthread</span><span class="c1">)</span></p> <p class="c4"><span class="c0">endif</span><span class="c1">(</span><span class="c0">APPLE</span><span class="c1">)</span></p></td></tr></tbody></table> <p class="c11 c15"><span class="c8 c2"></span></p> <p class="c11 c23 title" id="h.pu0xkfwwxrzi"><span class="c7 c2">Writing a Fuzz Target</span></p> <p class="c11"><span class="c8 c2">At this point, we&rsquo;ve assembled a chunk of XNU into a convenient library, but we still need to interact with it by writing a fuzz target. At first, I thought I might write many targets for different features, but I decided to write one monolithic target for this project. I&rsquo;m sure fine-grained targets could do a better job for functionality that&rsquo;s harder to fuzz, e.g., the TCP state machine, but we will stick to one for simplicity.</span></p> <p class="c11"><span class="c8 c2">We&rsquo;ll start by specifying an input grammar using protobuf, part of which is depicted below. This grammar is completely arbitrary and will be used by a corresponding C++ harness that we will write next. LibFuzzer has a plugin called libprotobuf-mutator that knows how to mutate protobuf messages. This will enable us to do grammar-based mutational fuzzing efficiently, while still leveraging coverage guided feedback. This is a very powerful combination.</span></p><a id="t.9d16a9b39fd12c4bd200524ebbec29df78b7c54e"></a><a id="t.8"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">message </span><span class="c13">Socket</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">Domain</span><span class="c0">&nbsp;domain </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">SoType</span><span class="c0">&nbsp;so_type </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">2</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">Protocol</span><span class="c0">&nbsp;protocol </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">3</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c17">// TODO: options, e.g. SO_ACCEPTCONN</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">message </span><span class="c13">Close</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">FileDescriptor</span><span class="c0">&nbsp;fd </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">message </span><span class="c13">SetSocketOpt</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; optional </span><span class="c13">Protocol</span><span class="c0">&nbsp;level </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; optional </span><span class="c13">SocketOptName</span><span class="c0">&nbsp;name </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">2</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c17">// TODO(nedwill): structure for val</span></p> <p class="c4"><span class="c0">&nbsp; optional bytes val </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">3</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; optional </span><span class="c13">FileDescriptor</span><span class="c0">&nbsp;fd </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">4</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">message </span><span class="c13">Command</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; oneof command </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c13">Packet</span><span class="c0">&nbsp;ip_input </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c13">SetSocketOpt</span><span class="c0">&nbsp;set_sock_opt </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">2</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c13">Socket</span><span class="c0">&nbsp;socket </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">3</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c13">Close</span><span class="c0">&nbsp;close </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">4</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">message </span><span class="c13">Session</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; repeated </span><span class="c13">Command</span><span class="c0">&nbsp;commands </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required bytes data_provider </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">2</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4 c18"><span>I left some TODO comments intact so you can see how the grammar can always be improved. As I&rsquo;ve done in similar fuzzing projects, I have a top-level message called </span><span class="c9">Session</span><span>&nbsp;that encapsulates a single fuzzer iteration or test case. This session contains a sequence of &ldquo;commands&rdquo; and a sequence of bytes that can be used when random, unstructured data is needed (e.g., when doing a </span><span class="c9">copyin</span><span>). Commands are syscalls or random packets, which in turn are their own messages that have associated data. For example, we might have a session that has a single Command message containing a &ldquo;Socket&rdquo; message. That Socket message has data associated with each argument to the syscall. In our C++-based target, it&rsquo;s our job to translate messages of this custom specification into real syscalls and related API calls. We inform libprotobuf-mutator that our fuzz target expects to receive one &ldquo;Session&rdquo; message at a time via the macro </span><span class="c9">DEFINE_BINARY_PROTO_FUZZER</span><span class="c8 c2">.<br></span></p><a id="t.041bf215fa328f955891b762d77faa759acbf246"></a><a id="t.9"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">DEFINE_BINARY_PROTO_FUZZER</span><span class="c1">(</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c13">Session</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">session</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c17">// ...</span></p> <p class="c4"><span class="c0">&nbsp; std</span><span class="c1">::</span><span class="c6">set</span><span class="c19">&lt;int&gt;</span><span class="c0">&nbsp;open_fds</span><span class="c1">;</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">for</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c13">Command</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">command </span><span class="c1">:</span><span class="c0">&nbsp;session</span><span class="c1">.</span><span class="c0">commands</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;retval </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">switch</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">command</span><span class="c1">.</span><span class="c0">command_case</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c6">case</span><span class="c0">&nbsp;</span><span class="c13">Command</span><span class="c1">::</span><span class="c0">kSocket</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;fd </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;err </span><span class="c1">=</span><span class="c0">&nbsp;socket_wrapper</span><span class="c1">(</span><span class="c0">command</span><span class="c1">.</span><span class="c0">socket</span><span class="c1">().</span><span class="c0">domain</span><span class="c1">(),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;command</span><span class="c1">.</span><span class="c0">socket</span><span class="c1">().</span><span class="c0">so_type</span><span class="c1">(),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;command</span><span class="c1">.</span><span class="c0">socket</span><span class="c1">().</span><span class="c0">protocol</span><span class="c1">(),</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">fd</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">err </span><span class="c1">==</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c17">// Make sure we&#39;re tracking fds properly.</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">open_fds</span><span class="c1">.</span><span class="c0">find</span><span class="c1">(</span><span class="c0">fd</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">!=</span><span class="c0">&nbsp;open_fds</span><span class="c1">.</span><span class="c6">end</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; printf</span><span class="c1">(</span><span class="c19">&quot;Found existing fd %d\n&quot;</span><span class="c1">,</span><span class="c0">&nbsp;fd</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">assert</span><span class="c1">(</span><span class="c6">false</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; open_fds</span><span class="c1">.</span><span class="c0">insert</span><span class="c1">(</span><span class="c0">fd</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">break</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c6">case</span><span class="c0">&nbsp;</span><span class="c13">Command</span><span class="c1">::</span><span class="c0">kClose</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; open_fds</span><span class="c1">.</span><span class="c0">erase</span><span class="c1">(</span><span class="c0">command</span><span class="c1">.</span><span class="c0">close</span><span class="c1">().</span><span class="c0">fd</span><span class="c1">());</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; close_wrapper</span><span class="c1">(</span><span class="c0">command</span><span class="c1">.</span><span class="c0">close</span><span class="c1">().</span><span class="c0">fd</span><span class="c1">(),</span><span class="c0">&nbsp;</span><span class="c6">nullptr</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">break</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c6">case</span><span class="c0">&nbsp;</span><span class="c13">Command</span><span class="c1">::</span><span class="c0">kSetSockOpt</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;s </span><span class="c1">=</span><span class="c0">&nbsp;command</span><span class="c1">.</span><span class="c0">set_sock_opt</span><span class="c1">().</span><span class="c0">fd</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;level </span><span class="c1">=</span><span class="c0">&nbsp;command</span><span class="c1">.</span><span class="c0">set_sock_opt</span><span class="c1">().</span><span class="c0">level</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;name </span><span class="c1">=</span><span class="c0">&nbsp;command</span><span class="c1">.</span><span class="c0">set_sock_opt</span><span class="c1">().</span><span class="c0">name</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; size_t size </span><span class="c1">=</span><span class="c0">&nbsp;command</span><span class="c1">.</span><span class="c0">set_sock_opt</span><span class="c1">().</span><span class="c0">val</span><span class="c1">().</span><span class="c0">size</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; std</span><span class="c1">::</span><span class="c0">unique_ptr</span><span class="c1">&lt;</span><span class="c6">char</span><span class="c1">[]&gt;</span><span class="c0">&nbsp;val</span><span class="c1">(</span><span class="c6">new</span><span class="c0">&nbsp;</span><span class="c6">char</span><span class="c1">[</span><span class="c0">size</span><span class="c1">]);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; memcpy</span><span class="c1">(</span><span class="c0">val</span><span class="c1">.</span><span class="c6">get</span><span class="c1">(),</span><span class="c0">&nbsp;command</span><span class="c1">.</span><span class="c0">set_sock_opt</span><span class="c1">().</span><span class="c0">val</span><span class="c1">().</span><span class="c0">data</span><span class="c1">(),</span><span class="c0">&nbsp;size</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; setsockopt_wrapper</span><span class="c1">(</span><span class="c0">s</span><span class="c1">,</span><span class="c0">&nbsp;level</span><span class="c1">,</span><span class="c0">&nbsp;name</span><span class="c1">,</span><span class="c0">&nbsp;val</span><span class="c1">.</span><span class="c6">get</span><span class="c1">(),</span><span class="c0">&nbsp;size</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">nullptr</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">break</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">While syscalls are typically a straightforward translation of the protobuf message, other commands are more complex. In order to improve the structure of randomly generated packets, I added custom message types that I then converted into the relevant on-the-wire structure before passing it into ip_input. Here&rsquo;s how this looks for TCP:</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.06a48b27c70500af6666b579bb650d3a174e966c"></a><a id="t.10"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">message </span><span class="c13">Packet</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; oneof packet </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c13">TcpPacket</span><span class="c0">&nbsp;tcp_packet </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">message </span><span class="c13">TcpPacket</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">IpHdr</span><span class="c0">&nbsp;ip_hdr </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">TcpHdr</span><span class="c0">&nbsp;tcp_hdr </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">2</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; optional bytes data </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">3</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">message </span><span class="c13">IpHdr</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 ip_hl </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">IpVersion</span><span class="c0">&nbsp;ip_v </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">2</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 ip_tos </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">3</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 ip_len </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">4</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 ip_id </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">5</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 ip_off </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">6</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 ip_ttl </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">7</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">Protocol</span><span class="c0">&nbsp;ip_p </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">8</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">InAddr</span><span class="c0">&nbsp;ip_src </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">9</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">InAddr</span><span class="c0">&nbsp;ip_dst </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">10</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">message </span><span class="c13">TcpHdr</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">Port</span><span class="c0">&nbsp;th_sport </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">Port</span><span class="c0">&nbsp;th_dport </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">2</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">TcpSeq</span><span class="c0">&nbsp;th_seq </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">3</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c13">TcpSeq</span><span class="c0">&nbsp;th_ack </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">4</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 th_off </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">5</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; repeated </span><span class="c13">TcpFlag</span><span class="c0">&nbsp;th_flags </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">6</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 th_win </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">7</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 th_sum </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">8</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required uint32 th_urp </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">9</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c17">// Ned&#39;s extensions</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c6">bool</span><span class="c0">&nbsp;is_pure_syn </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">10</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; required </span><span class="c6">bool</span><span class="c0">&nbsp;is_pure_ack </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">11</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c15 c18"><span class="c8 c2"></span></p> <p class="c4 c18"><span>Unfortunately, protobuf doesn&rsquo;t support a uint8 type, so I had to use uint32 for some fields. That&rsquo;s some lost fuzzing performance. You can also see some synthetic TCP header flags I added to make certain flag combinations more likely: </span><span class="c9">is_pure_syn</span><span>&nbsp;and </span><span class="c9">is_pure_ack</span><span class="c8 c2">. Now I have to write some code to stitch together a valid packet from these nested fields. Shown below is the code to handle just the TCP header.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.b04bea361f4572715c957400db3964f6b12a92e1"></a><a id="t.11"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">std</span><span class="c1">::</span><span class="c6">string</span><span class="c0">&nbsp;get_tcp_hdr</span><span class="c1">(</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c13">TcpHdr</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">hdr</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;tcphdr tcphdr </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_sport </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">unsigned</span><span class="c0">&nbsp;</span><span class="c6">short</span><span class="c1">)</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">th_sport</span><span class="c1">(),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_dport </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">unsigned</span><span class="c0">&nbsp;</span><span class="c6">short</span><span class="c1">)</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">th_dport</span><span class="c1">(),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_seq </span><span class="c1">=</span><span class="c0">&nbsp;__builtin_bswap32</span><span class="c1">(</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">th_seq</span><span class="c1">()),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_ack </span><span class="c1">=</span><span class="c0">&nbsp;__builtin_bswap32</span><span class="c1">(</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">th_ack</span><span class="c1">()),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_off </span><span class="c1">=</span><span class="c0">&nbsp;hdr</span><span class="c1">.</span><span class="c0">th_off</span><span class="c1">(),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_flags </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_win </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">unsigned</span><span class="c0">&nbsp;</span><span class="c6">short</span><span class="c1">)</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">th_win</span><span class="c1">(),</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_sum </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c17">// TODO(nedwill): calculate the checksum instead of skipping it</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">.</span><span class="c0">th_urp </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">unsigned</span><span class="c0">&nbsp;</span><span class="c6">short</span><span class="c1">)</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">th_urp</span><span class="c1">(),</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">};</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">for</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c6">int</span><span class="c0">&nbsp;flag </span><span class="c1">:</span><span class="c0">&nbsp;hdr</span><span class="c1">.</span><span class="c0">th_flags</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; tcphdr</span><span class="c1">.</span><span class="c0">th_flags </span><span class="c1">^=</span><span class="c0">&nbsp;flag</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c17">// Prefer pure syn</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">is_pure_syn</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; tcphdr</span><span class="c1">.</span><span class="c0">th_flags </span><span class="c1">&amp;=</span><span class="c0">&nbsp;</span><span class="c1">~(</span><span class="c0">TH_RST </span><span class="c1">|</span><span class="c0">&nbsp;TH_ACK</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; tcphdr</span><span class="c1">.</span><span class="c0">th_flags </span><span class="c1">|=</span><span class="c0">&nbsp;TH_SYN</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span><span class="c0">&nbsp;</span><span class="c6">else</span><span class="c0">&nbsp;</span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">hdr</span><span class="c1">.</span><span class="c0">is_pure_ack</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; tcphdr</span><span class="c1">.</span><span class="c0">th_flags </span><span class="c1">&amp;=</span><span class="c0">&nbsp;</span><span class="c1">~(</span><span class="c0">TH_RST </span><span class="c1">|</span><span class="c0">&nbsp;TH_SYN</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; tcphdr</span><span class="c1">.</span><span class="c0">th_flags </span><span class="c1">|=</span><span class="c0">&nbsp;TH_ACK</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; std</span><span class="c1">::</span><span class="c6">string</span><span class="c0">&nbsp;dat</span><span class="c1">((</span><span class="c6">char</span><span class="c0">&nbsp;</span><span class="c1">*)&amp;</span><span class="c0">tcphdr</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">char</span><span class="c0">&nbsp;</span><span class="c1">*)&amp;</span><span class="c0">tcphdr </span><span class="c1">+</span><span class="c0">&nbsp;</span><span class="c6">sizeof</span><span class="c1">(</span><span class="c0">tcphdr</span><span class="c1">));</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;dat</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c18"><span class="c8 c2"><br>As you can see, I make liberal use of a custom grammar to enable better quality fuzzing. These efforts are worth it, as randomizing high level structure is more efficient. It will also be easier for us to interpret crashing test cases later as they will have the same high level representation.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c11 c23 title" id="h.91xkgwarn2ge"><span class="c2 c7">High-Level Emulation</span></p> <p class="c4 c18"><span class="c8 c2">Now that we have the code building and an initial fuzz target running, we begin the first pass at implementing all of the stubbed code that is reachable by our fuzz target. Because we have a fuzz target that builds and runs, we now get instant feedback about which functions our target hits. Some core functionality has to be supported before we can find any bugs, so the first attempt to run the fuzzer deserves its own development phase. For example, until dynamic memory allocation is supported, almost no kernel code we try to cover will work considering how heavily such code is used.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">We&rsquo;ll be implementing our stubbed functions with fake variants that attempt to have the same semantics. For example, when testing code that uses an external database library, you could replace the database with a simple in-memory implementation. If you don&rsquo;t care about finding database bugs, this often makes fuzzing simpler and more robust. For some kernel subsystems unrelated to networking we can use entirely different or null implementations. This process is reminiscent of high-level emulation, an idea used in game console emulation. Rather than aiming to emulate hardware, you can try to preserve the semantics but use a custom implementation of the API. Because we only care about testing networking, this is how we approach faking subsystems in this project.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c11"><span>I always start by looking at the original function implementation. If it&rsquo;s possible, I just link in that code as well. But some functionality isn&rsquo;t compatible with our fuzzer and must be faked. For example, </span><span class="c9">zalloc</span><span>&nbsp;should call the userland malloc since virtual memory is already managed by our host kernel and we have allocator facilities available. Similarly, </span><span class="c9">copyin</span><span>&nbsp;and </span><span class="c9">copyout</span><span>&nbsp;need to be faked as they no longer serve to copy data between user and kernel pages. Sometimes we also just &ldquo;nop&rdquo; out functionality that we don&rsquo;t care about. We&rsquo;ll cover these decisions in more detail later in the &ldquo;High-Level Emulation&rdquo; phase. Note that by implementing these stubs lazily whenever our fuzz target hits them, we immediately reduce the work in handling all the unrelated functions by an order of magnitude. It&rsquo;s easier to stay motivated when you only implement fakes for functions that are used by the target code. </span><span>This approach successfully saved me a lot of time</span><span class="c8 c2">&nbsp;and I&rsquo;ve used it on subsequent projects as well. At the time of writing, I have 398 stubbed functions, about 250 functions that are trivially faked (return 0 or void functions that do nothing), and about 25 functions that I faked myself (almost all related to porting the memory allocation systems to userland).</span></p><h1 class="c20 c18" id="h.ltz0op6gg9n7"><span class="c27 c2">Booting Up</span></h1> <p class="c4 c18"><span>As soon as we start running the fuzzer, we&rsquo;ll run into a snag: many resources require a one-time initialization that happens on boot. The BSD half of the kernel is mostly initialized by calling the </span><span class="c9">bsd_init</span><span>&nbsp;function. That function, in turn, calls several subsystem-specific initialization functions. Keeping with the theme of supporting a minimally necessary subset of the kernel, rather than call </span><span class="c9">bsd_init</span><span class="c8 c2">, we create a new function that only initializes parts of the kernel as needed.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">Here&rsquo;s an example crash that occurs without the one time kernel bootup initialization:</span></p><a id="t.7dee2e6aabb2ca9a391d0f364d5d1fcd8b821d76"></a><a id="t.12"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#7 0x7effbc464ad0 in zalloc /source/build3/../fuzz/zalloc.c:35:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#8 0x7effbb62eab4 in pipepair_alloc /source/build3/../bsd/kern/sys_pipe.c:634:24</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#9 0x7effbb62ded5 in pipe /source/build3/../bsd/kern/sys_pipe.c:425:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#10 0x7effbc4588ab in pipe_wrapper /source/build3/../fuzz/syscall_wrappers.c:216:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#11 0x4ee1a4 in TestOneProtoInput(Session const&amp;) /source/build3/../fuzz/net_fuzzer.cc:979:19</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">Our zalloc implementation (covered in the next section) failed because the pipe zone wasn&rsquo;t yet initialized:</span></p><a id="t.28d23a3828667c4eb9bd8e3032e358cb84291c9e"></a><a id="t.13"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">static</span><span class="c0">&nbsp;</span><span class="c6">int</span></p> <p class="c4"><span class="c0">pipepair_alloc</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;pipe </span><span class="c1">**</span><span class="c0">rp_out</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">struct</span><span class="c0">&nbsp;pipe </span><span class="c1">**</span><span class="c0">wp_out</span><span class="c1">)</span></p> <p class="c4"><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;pipepair </span><span class="c1">*</span><span class="c0">pp </span><span class="c1">=</span><span class="c0">&nbsp;zalloc</span><span class="c1">(</span><span class="c0">pipe_zone</span><span class="c1">);</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">Scrolling up in sys_pipe.c, we see where that zone is initialized:</span></p><a id="t.6cb4ba0329612fe0bfce12d0efd46322d7f90626"></a><a id="t.14"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">void</span></p> <p class="c4"><span class="c0">pipeinit</span><span class="c1">(</span><span class="c6">void</span><span class="c1">)</span></p> <p class="c4"><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; nbigpipe </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; vm_size_t zone_size</span><span class="c1">;</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; zone_size </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">8192</span><span class="c0">&nbsp;</span><span class="c1">*</span><span class="c0">&nbsp;</span><span class="c6">sizeof</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;pipepair</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; pipe_zone </span><span class="c1">=</span><span class="c0">&nbsp;zinit</span><span class="c1">(</span><span class="c6">sizeof</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;pipepair</span><span class="c1">),</span><span class="c0">&nbsp;zone_size</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c3">4096</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c19">&quot;pipe zone&quot;</span><span class="c1">);</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>Sure enough, this function is called by </span><span class="c9">bsd_init</span><span class="c8 c2">. By adding that to our initial setup function the zone works as expected. After some development cycles spent supporting all the needed bsd_init function calls, we have the following:</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.c36531451445cbd3070043535c88b4e9f6dc8668"></a><a id="t.15"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">__attribute__</span><span class="c1">((</span><span class="c0">visibility</span><span class="c1">(</span><span class="c19">&quot;default&quot;</span><span class="c1">)))</span><span class="c0">&nbsp;</span><span class="c6">bool</span><span class="c0">&nbsp;initialize_network</span><span class="c1">()</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; mcache_init</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; mbinit</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; eventhandler_init</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; pipeinit</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; dlil_init</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; socketinit</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; domaininit</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; loopattach</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; ether_family_init</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; tcp_cc_init</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; net_init_run</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;res </span><span class="c1">=</span><span class="c0">&nbsp;necp_init</span><span class="c1">();</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">assert</span><span class="c1">(!</span><span class="c0">res</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c6">true</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c18"><span><br>The original </span><span class="c9">bsd_init</span><span>&nbsp;is 683 lines long, but our </span><span class="c9">initialize_network</span><span class="c8 c2">&nbsp;clone is the preceding short snippet. I want to remark how cool I found it that you could &ldquo;boot&rdquo; a kernel like this and have everything work so long as you implemented all the relevant stubs. It just goes to show a surprising fact: a significant amount of kernel code is portable, and simple steps can be taken to make it testable. These codebases can be modernized without being fully rewritten. As this &ldquo;boot&rdquo; relies on dynamic allocation, let&rsquo;s look at how I implemented that next.</span></p><h1 class="c18 c20" id="h.9dofj4t03k0j"><span class="c27 c2">Dynamic Memory Allocation</span></h1> <p class="c4 c18"><span class="c8 c2">Providing a virtual memory abstraction is a fundamental goal of most kernels, but the good news is this is out of scope for this project (this is left as an exercise for the reader). Because networking already assumes working virtual memory, the network stack functions almost entirely on top of high-level allocator APIs. This makes the subsystem amenable to &ldquo;high-level emulation&rdquo;. We can create a thin shim layer that intercepts XNU specific allocator calls and translates them to the relevant host APIs.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">In practice, we have to handle three types of allocations for this project: &ldquo;classic&rdquo; allocations (malloc/calloc/free), zone allocations (zalloc), and mbuf (memory buffers). The first two types are more fundamental allocation types used across XNU, while mbufs are a common data structure used in low-level networking code.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>The zone allocator is reasonably complicated, but we use a simplified model for our purposes: we just track the size assigned to a zone when it is created and make sure we malloc that size when zalloc is later called using the initialized zone. This could undoubtedly be modeled better, but this initial model worked quite well for the types of bugs I was looking for. In practice, this simplification affects exploitability, but we aren&rsquo;t worried about that for a fuzzing project as we can assess that manually once we discover an issue. As you can see below, I created a custom zone type that simply stored the configured size, knowing that my zinit would return an opaque pointer that would be passed to my zalloc implementation, which could then use </span><span class="c9">calloc</span><span>&nbsp;to service the request. </span><span class="c9">zfree</span><span class="c8 c2">&nbsp;simply freed the requested bytes and ignored the zone, as allocation sizes are tracked by the host malloc already.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.7e8e3471c54f0a0758208cb59ca503fca5b8d03b"></a><a id="t.16"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">struct</span><span class="c0">&nbsp;zone </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; uintptr_t size</span><span class="c1">;</span></p> <p class="c4"><span class="c1">};</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">struct</span><span class="c0">&nbsp;zone</span><span class="c1">*</span><span class="c0">&nbsp;zinit</span><span class="c1">(</span><span class="c0">uintptr_t size</span><span class="c1">,</span><span class="c0">&nbsp;uintptr_t max</span><span class="c1">,</span><span class="c0">&nbsp;uintptr_t alloc</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c6">const</span><span class="c0">&nbsp;</span><span class="c6">char</span><span class="c1">*</span><span class="c0">&nbsp;name</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;zone</span><span class="c1">*</span><span class="c0">&nbsp;zone </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;zone</span><span class="c1">*)</span><span class="c0">calloc</span><span class="c1">(</span><span class="c3">1</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">sizeof</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;zone</span><span class="c1">));</span></p> <p class="c4"><span class="c0">&nbsp; zone</span><span class="c1">-&gt;</span><span class="c0">size </span><span class="c1">=</span><span class="c0">&nbsp;size</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;zone</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">void</span><span class="c1">*</span><span class="c0">&nbsp;zalloc</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;zone</span><span class="c1">*</span><span class="c0">&nbsp;zone</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">assert</span><span class="c1">(</span><span class="c0">zone </span><span class="c1">!=</span><span class="c0">&nbsp;NULL</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;calloc</span><span class="c1">(</span><span class="c3">1</span><span class="c1">,</span><span class="c0">&nbsp;zone</span><span class="c1">-&gt;</span><span class="c0">size</span><span class="c1">);</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">void</span><span class="c0">&nbsp;zfree</span><span class="c1">(</span><span class="c6">void</span><span class="c1">*</span><span class="c0">&nbsp;zone</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">void</span><span class="c1">*</span><span class="c0">&nbsp;dat</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">(</span><span class="c6">void</span><span class="c1">)</span><span class="c0">zone</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; free</span><span class="c1">(</span><span class="c0">dat</span><span class="c1">);</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">Kalloc, kfree, and related functions were passed through to malloc and free as well. You can see fuzz/zalloc.c for their implementations. Mbufs (memory buffers) are more work to implement because they contain considerable metadata that is exposed to the &ldquo;client&rdquo; networking code.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.3cadcc6e539811e51cc5416c071def6b93755bc1"></a><a id="t.17"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">struct</span><span class="c0">&nbsp;m_hdr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;mbuf &nbsp; &nbsp; </span><span class="c1">*</span><span class="c0">mh_next</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; </span><span class="c17">/* next buffer in chain */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;mbuf &nbsp; &nbsp; </span><span class="c1">*</span><span class="c0">mh_nextpkt</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp;</span><span class="c17">/* next chain in queue/record */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; caddr_t &nbsp; &nbsp; &nbsp; &nbsp; mh_data</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c17">/* location of data */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; int32_t &nbsp; &nbsp; &nbsp; &nbsp; mh_len</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c17">/* amount of data in this mbuf */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; u_int16_t &nbsp; &nbsp; &nbsp; mh_type</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c17">/* type of data in this mbuf */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; u_int16_t &nbsp; &nbsp; &nbsp; mh_flags</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; </span><span class="c17">/* flags; see below */</span></p> <p class="c4"><span class="c1">};</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c17">/*</span></p> <p class="c4"><span class="c17">&nbsp;* The mbuf object</span></p> <p class="c4"><span class="c17">&nbsp;*/</span></p> <p class="c4"><span class="c6">struct</span><span class="c0">&nbsp;mbuf </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;m_hdr m_hdr</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">union</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;pkthdr MH_pkthdr</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c17">/* M_PKTHDR set */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">union</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;m_ext MH_ext</span><span class="c1">;</span><span class="c0">&nbsp;&nbsp; &nbsp;</span><span class="c17">/* M_EXT set */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">char</span><span class="c0">&nbsp;&nbsp; &nbsp;MH_databuf</span><span class="c1">[</span><span class="c0">_MHLEN</span><span class="c1">];</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span><span class="c0">&nbsp;MH_dat</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span><span class="c0">&nbsp;MH</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">char</span><span class="c0">&nbsp;&nbsp; &nbsp;M_databuf</span><span class="c1">[</span><span class="c0">_MLEN</span><span class="c1">];</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c17">/* !M_PKTHDR, !M_EXT */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span><span class="c0">&nbsp;M_dat</span><span class="c1">;</span></p> <p class="c4"><span class="c1">};</span></p></td></tr></tbody></table> <p class="c11"><span><br>I didn&rsquo;t include the </span><span class="c9">pkthdr</span><span>&nbsp;nor </span><span class="c9">m_ext</span><span>&nbsp;structure definitions, but they are nontrivial (you can see for yourself in bsd/sys/mbuf.h). A lot of trial and error was needed to create a simplified mbuf format that would work. In practice, I use an inline buffer when possible and, when necessary, locate the data in one large external buffer and set the </span><span class="c9">M_EXT</span><span>&nbsp;flag. As these allocations must be aligned, I use </span><span class="c9">posix_memalign</span><span>&nbsp;to create them, rather than </span><span class="c9">malloc</span><span class="c8 c2">. Fortunately ASAN can help manage these allocations, so we can detect some bugs with this modification.</span></p> <p class="c11"><span>Two bugs I reported via the </span><span>Project Z</span><span>ero tracker highlight the benefit of the heap-based mbuf implementation</span><span>. </span><span>In the </span><span class="c14"><a class="c121" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1981">first report</a></span><span>, I detected an mbuf double free using ASAN. While the </span><span class="c9">m_free</span><span>&nbsp;implementation tries to detect double frees by checking the state of the allocation, ASAN goes even further by quarantining recently freed allocations to detect the bug. In this case, it looks like the fuzzer would have found the bug either way, but it was impressive. The </span><span class="c14"><a class="c121" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1976">second issue</a></span><span class="c2 c8">&nbsp;linked is much subtler and requires some instrumentation to detect the bug, as it is a use after free read of an mbuf:</span></p><a id="t.a88ece0e2c57e078b87f3bf379cfbeb8837c55ed"></a><a id="t.18"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c1">==</span><span class="c3">22568</span><span class="c1">==</span><span class="c0">ERROR</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c13">AddressSanitizer</span><span class="c1">:</span><span class="c0">&nbsp;heap</span><span class="c1">-</span><span class="c6">use</span><span class="c1">-</span><span class="c0">after</span><span class="c1">-</span><span class="c0">free on address </span><span class="c3">0x61500026afe5</span><span class="c0">&nbsp;at pc </span><span class="c3">0x7ff60f95cace</span><span class="c0">&nbsp;bp </span><span class="c3">0x7ffd4d5617b0</span><span class="c0">&nbsp;sp </span><span class="c3">0x7ffd4d5617a8</span></p> <p class="c4"><span class="c0">READ of size </span><span class="c3">1</span><span class="c0">&nbsp;at </span><span class="c3">0x61500026afe5</span><span class="c0 c2">&nbsp;thread T0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#0 0x7ff60f95cacd in tcp_input bsd/netinet/tcp_input.c:5029:25</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#1 0x7ff60f949321 in tcp6_input bsd/netinet/tcp_input.c:1062:2</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#2 0x7ff60fa9263c in ip6_input bsd/netinet6/ip6_input.c:1277:10</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c3">0x61500026afe5</span><span class="c0">&nbsp;</span><span class="c6">is</span><span class="c0">&nbsp;located </span><span class="c3">229</span><span class="c0">&nbsp;bytes inside of </span><span class="c3">256</span><span class="c1">-</span><span class="c6">byte</span><span class="c0">&nbsp;region </span><span class="c1">[</span><span class="c3">0x61500026af00</span><span class="c1">,</span><span class="c3">0x61500026b000</span><span class="c1">)</span></p> <p class="c4"><span class="c0">freed </span><span class="c6">by</span><span class="c0">&nbsp;thread T0 here</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#0 0x4a158d in free /b/swarming/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#1 0x7ff60fb7444d in m_free fuzz/zalloc.c:220:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#2 0x7ff60f4e3527 in m_freem bsd/kern/uipc_mbuf.c:4842:7</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#3 0x7ff60f5334c9 in sbappendstream_rcvdemux bsd/kern/uipc_socket2.c:1472:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#4 0x7ff60f95821d in tcp_input bsd/netinet/tcp_input.c:5019:8</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#5 0x7ff60f949321 in tcp6_input bsd/netinet/tcp_input.c:1062:2</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x7ff60fa9263c in ip6_input bsd/netinet6/ip6_input.c:1277:10</span></p></td></tr></tbody></table> <p class="c11"><span><br>Apple managed to catch this issue before I reported it, fixing it in iOS 13. I believe Apple has added some internal hardening or testing for mbufs that caught this bug. It could be anything from a hardened mbuf allocator like </span><span class="c14"><a class="c121" href="https://llvm.org/docs/GwpAsan.html">GWP-ASAN</a></span><span class="c8 c2">, to an internal ARM MTE test, to simple auditing, but it was really cool to see this issue detected in this way, and also that Apple was proactive enough to find this themselves.</span></p><h1 class="c20 c18" id="h.d95bqayxtdtc"><span class="c2 c27">Accessing User Memory</span></h1> <p class="c4 c18"><span>When talking about this project with a fellow attendee at a fuzzing conference, their biggest question was how I handled user memory access. Kernels are never supposed to trust pointers provided by user-space, so whenever the kernel wants to access memory-mapped in userspace, it goes through intermediate functions </span><span class="c9">copyin</span><span>&nbsp;and </span><span class="c9">copyout</span><span class="c8 c2">. By replacing these functions with our fake implementations, we can supply fuzzer-provided input to the tested code. The real kernel would have done the relevant copies from user to kernel pages. Because these copies are driven by the target code and not our testcase, I added a buffer in the protobuf specification to be used to service these requests.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>Here&rsquo;s a backtrace from our stub before we implement `copyin`</span><span>.</span><span>&nbsp;As you can see, when calling the `recvfrom` syscall, our fuzzer passed in a pointer as an argument.</span></p><a id="t.95cfad74e7fc7217ee4a1ac5e48dea5ca2a33f6a"></a><a id="t.19"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x7fe1176952f3 in Assert /source/build3/../fuzz/stubs.c:21:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#7 0x7fe11769a110 in copyin /source/build3/../fuzz/fake_impls.c:408:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#8 0x7fe116951a18 in __copyin_chk /source/build3/../bsd/libkern/copyio.h:47:9</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#9 0x7fe116951a18 in recvfrom_nocancel /source/build3/../bsd/kern/uipc_syscalls.c:2056:11</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#10 0x7fe117691a86 in recvfrom_nocancel_wrapper /source/build3/../fuzz/syscall_wrappers.c:244:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#11 0x4e933a in TestOneProtoInput(Session const&amp;) /source/build3/../fuzz/net_fuzzer.cc:936:9</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#12 0x4e43b8 in LLVMFuzzerTestOneInput /source/build3/../fuzz/net_fuzzer.cc:631:1</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>I&rsquo;ve extended the copyin specification with my fuzzer-specific semantics: when the pointer </span><span class="c9">(void*)1</span><span>&nbsp;is passed as an address, we interpret this as a request to fetch arbitrary bytes. Otherwise, we copy directly from that virtual memory address. This way, we can begin by passing </span><span class="c9">(void*)1</span><span class="c8 c2">&nbsp;everywhere in the fuzz target to get as much cheap coverage as possible. Later, as we want to construct well-formed data to pass into syscalls, we build the data in the protobuf test case handler and pass a real pointer to it, allowing it to be copied. This flexibility saves us time while permitting the construction of highly-structured data inputs as we see fit.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.e72a3ef67035e7b412dce9ccdc54b3659668a297"></a><a id="t.20"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">int</span><span class="c0">&nbsp;__attribute__</span><span class="c1">((</span><span class="c0">warn_unused_result</span><span class="c1">))</span></p> <p class="c4"><span class="c0">copyin</span><span class="c1">(</span><span class="c6">void</span><span class="c1">*</span><span class="c0">&nbsp;user_addr</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">void</span><span class="c1">*</span><span class="c0">&nbsp;kernel_addr</span><span class="c1">,</span><span class="c0">&nbsp;size_t nbytes</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c17">// Address 1 means use fuzzed bytes, otherwise use real bytes.</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c17">// NOTE: this does not support nested useraddr.</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">user_addr </span><span class="c1">!=</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">void</span><span class="c1">*)</span><span class="c3">1</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; memcpy</span><span class="c1">(</span><span class="c0">kernel_addr</span><span class="c1">,</span><span class="c0">&nbsp;user_addr</span><span class="c1">,</span><span class="c0">&nbsp;nbytes</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">get_fuzzed_bool</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c1">-</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; get_fuzzed_bytes</span><span class="c1">(</span><span class="c0">kernel_addr</span><span class="c1">,</span><span class="c0">&nbsp;nbytes</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4 c18"><span>Copyout is designed similarly. We often don&rsquo;t care about the data copied out; we just care about the safety of the accesses. For that reason, we make sure to memcpy from the source buffer in all cases, using a temporary buffer when a copy to </span><span class="c9">(void*)1</span><span>&nbsp;occurs. If the kernel copies out of bounds or from freed memory, for example, ASAN will catch it and inform us about a memory disclosure vulnerability.</span></p><h1 class="c20 c18" id="h.bydr5qowo002"><span class="c27 c2">Synchronization and Threads</span></h1> <p class="c4 c18"><span>Among the many changes made to XNU&rsquo;s behavior to support this project, perhaps the most extensive and invasive are the changes I made to the synchronization and threading model. Before beginning this project, I had spent over a year working on Chrome browser process research, where high level &ldquo;sequences&rdquo; are </span><span class="c14"><a class="c121" href="https://chromium.googlesource.com/chromium/src/+/master/docs/threading_and_tasks.md#prefer-sequences-to-physical-threads">preferred to using physical threads</a></span><span>. Despite a paucity of data races, Chrome still had sequence-related bugs that were triggered by randomly servicing some of the pending work in between performing synchronous IPC calls. In an exploit for a bug found by the </span><span class="c14"><a class="c121" href="https://source.chromium.org/chromium/chromium/src/+/master:content/browser/appcache/appcache_fuzzer.cc;l=275;drc=db9ae7941adc1d95c943accce9e0151d265fd640">AppCache fuzzer</a></span><span>, </span><span class="c8 c2">sleep calls were needed to get the asynchronous work to be completed before queueing up some more work synchronously. So I already knew that asynchronous continuation-passing style concurrency could have exploitable bugs that are easy to discover with this fuzzing approach.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>I suspected I could find similar bugs if I used a similar model for sockfuzzer. Because XNU uses multiple kernel threads in its networking stack, I would have to port it to a cooperative style. To do this, I provided no-op implementations for all of the thread management functions and sync primitives, and instead randomly called the work functions that would have been called by the real threads. This involved modifying code: most worker threads run in a loop, processing new work as it comes in. I modified these infinitely looping helper functions to do one iteration of work and exposed them to the fuzzer frontend. Then I called them randomly as part of the protobuf message. The main benefit of doing the project this way was improved performance and determinism. Places where the kernel could block the fuzzer were modified to return early. Overall, it was a lot simpler and easier to manage a single-threaded process. But this decision did not end up yielding as many bugs as I had hoped. For example, I suspected that interleaving garbage collection of various network-related structures with syscalls would be more effective. It did achieve the goal of removing threading-related headaches from deploying the fuzzer, but this is a serious weakness that I would like to address in future fuzzer revisions.</span></p><h1 class="c20 c18" id="h.kmj0lqsi4gzm"><span class="c27 c2">Randomness</span></h1> <p class="c4 c18"><span>Randomness is another service provided by kernels to userland (e.g. /dev/random) and in-kernel services requiring it. This is easy to emulate: we can just return as many bytes as were requested from the current test case&rsquo;s </span><span class="c9">data_provider</span><span class="c8 c2">&nbsp;field.</span></p><h1 class="c20 c18" id="h.uqavuzi2havy"><span class="c27 c2">Authentication</span></h1> <p class="c4 c18"><span class="c8 c2">XNU features some mechanisms (KAuth, mac checks, user checks) to determine whether a given syscall is permissible. Because of the importance and relative rarity of bugs in XNU, and my willingness to triage false positives, I decided to allow all actions by default. For example, the TCP multipath code requires a special entitlement, but disabling this functionality precludes us from finding Ian&rsquo;s multipath vulnerability. Rather than fuzz only code accessible inside the app sandbox, I figured I would just triage whatever comes up and report it with the appropriate severity in mind.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">For example, when we create a socket, the kernel checks whether the running process is allowed to make a socket of the given domain, type, and protocol provided their KAuth credentials:</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.18282f1e8a60e62e63d117b754876dbe5736c0c5"></a><a id="t.21"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">static</span><span class="c0">&nbsp;</span><span class="c6">int</span></p> <p class="c4"><span class="c0">socket_common</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;proc </span><span class="c1">*</span><span class="c0">p</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;domain</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;type</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;protocol</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; pid_t epid</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; int32_t </span><span class="c1">*</span><span class="c0">retval</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;</span><span class="c6">delegate</span><span class="c1">)</span></p> <p class="c4"><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;socket </span><span class="c1">*</span><span class="c0">so</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;fileproc </span><span class="c1">*</span><span class="c0">fp</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;fd</span><span class="c1">,</span><span class="c0">&nbsp;error</span><span class="c1">;</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; AUDIT_ARG</span><span class="c1">(</span><span class="c0">socket</span><span class="c1">,</span><span class="c0">&nbsp;domain</span><span class="c1">,</span><span class="c0">&nbsp;type</span><span class="c1">,</span><span class="c0">&nbsp;protocol</span><span class="c1">);</span></p> <p class="c4"><span class="c17">#if CONFIG_MACF_SOCKET_SUBSET</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">((</span><span class="c0">error </span><span class="c1">=</span><span class="c0">&nbsp;mac_socket_check_create</span><span class="c1">(</span><span class="c0">kauth_cred_get</span><span class="c1">(),</span><span class="c0">&nbsp;domain</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; type</span><span class="c1">,</span><span class="c0">&nbsp;protocol</span><span class="c1">))</span><span class="c0">&nbsp;</span><span class="c1">!=</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;error</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c17">#endif</span><span class="c0">&nbsp;</span><span class="c17">/* MAC_SOCKET_SUBSET */</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">When we reach this function in our fuzzer, we trigger an assert crash as this functionality was &nbsp;stubbed.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.302eee1cbdf895a4dc039cf6ce90b0c2bd2abfd3"></a><a id="t.22"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x7f58f49b53f3 in Assert /source/build3/../fuzz/stubs.c:21:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#7 0x7f58f49ba070 in kauth_cred_get /source/build3/../fuzz/fake_impls.c:272:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#8 0x7f58f3c70889 in socket_common /source/build3/../bsd/kern/uipc_syscalls.c:242:39</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#9 0x7f58f3c7043a in socket /source/build3/../bsd/kern/uipc_syscalls.c:214:9</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#10 0x7f58f49b45e3 in socket_wrapper /source/build3/../fuzz/syscall_wrappers.c:371:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#11 0x4e8598 in TestOneProtoInput(Session const&amp;) /source/build3/../fuzz/net_fuzzer.cc:655:19</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>Now, we need to implement </span><span class="c9">kauth_cred_get</span><span>. In this case, we return a (void*)1 pointer so that NULL checks on the value will pass (and if it turns out we need to model this correctly, we&rsquo;ll crash again when the pointer is used).</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.5e1e8bf64388f5e50d984d841c5a6696fd7eae46"></a><a id="t.23"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">void</span><span class="c1">*</span><span class="c0">&nbsp;kauth_cred_get</span><span class="c1">()</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c6">void</span><span class="c1">*)</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">Now we crash actually checking the KAuth permissions.<br></span></p><a id="t.c32adfdc5da002864f42356336383091ed0936f9"></a><a id="t.24"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x7fbe9219a3f3 in Assert /source/build3/../fuzz/stubs.c:21:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#7 0x7fbe9219f100 in mac_socket_check_create /source/build3/../fuzz/fake_impls.c:312:33</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#8 0x7fbe914558a3 in socket_common /source/build3/../bsd/kern/uipc_syscalls.c:242:15</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#9 0x7fbe9145543a in socket /source/build3/../bsd/kern/uipc_syscalls.c:214:9</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#10 0x7fbe921995e3 in socket_wrapper /source/build3/../fuzz/syscall_wrappers.c:371:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#11 0x4e8598 in TestOneProtoInput(Session const&amp;) /source/build3/../fuzz/net_fuzzer.cc:655:19</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#12 0x4e76c2 in LLVMFuzzerTestOneInput /source/build3/../fuzz/net_fuzzer.cc:631:1</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">Now we simply return 0 and move on.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.0d0274614707b5c947a1eb6e9d303107416a6c97"></a><a id="t.25"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">int</span><span class="c0">&nbsp;mac_socket_check_create</span><span class="c1">()</span><span class="c0">&nbsp;</span><span class="c1">{</span><span class="c0">&nbsp;</span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span><span class="c0">&nbsp;</span><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">As you can see, we don&rsquo;t always need to do a lot of work to fake functionality. We can opt for a much simpler model that still gets us the results we want.<br></span></p> <p class="c11 c23 title" id="h.nu1k8a1bgzhy"><span>Coverage Guided Development</span></p> <p class="c11"><span>We&rsquo;ve paid a sizable initial cost to implement this fuzz target, but we&rsquo;re now entering the longest and most fun stage of the project: iterating and maintaining the fuzzer. We begin by running the fuzzer continuously (in my case, I ensured it could run on ClusterFuzz). A day of work then consists of fetching the latest corpus, running a clang-coverage visualization pass over it, and viewing the report. While initially most of the work involved fixing assertion failures to get the fuzzer working, we now look for silent implementation deficiencies only visible in the coverage reports. A snippet from the report looks like the following:</span></p> <p class="c11"></p> <p class="c4 c18"><span><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjypy5nffIIMxqcIAkEku-SJldrsLbyXhU-th0AbxjTCf8e8hM-L4hpsxAJUbibDeaTMsiHpirbmlNqKqSa3eIdd1bJYm9HtfDoVTNbItsbu7xdZDq5gG9eK5l8qHEblS7LoyglGzTqzn_1l5XXNIBf9YOdT2JiJ2_6wiE9_Yd7KrDaM-MhERHw4myg/s658/image4.png" style="display: block; padding: 1em 0;text-align: center;"><img alt="Several lines of code have a column indicating that they have been covered tens of thousands of times. Below them, you can see a switch statement for handling the parsing of IP options. Only the default case is covered approximately fifty thousand times, while the routing record options are covered 0 times." border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjypy5nffIIMxqcIAkEku-SJldrsLbyXhU-th0AbxjTCf8e8hM-L4hpsxAJUbibDeaTMsiHpirbmlNqKqSa3eIdd1bJYm9HtfDoVTNbItsbu7xdZDq5gG9eK5l8qHEblS7LoyglGzTqzn_1l5XXNIBf9YOdT2JiJ2_6wiE9_Yd7KrDaM-MhERHw4myg/s658/image4.png" style="max-height: 750px; max-width: 600px;" /></a></span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c11"><span class="c8 c2">This excerpt from IP option handling shows that we don&rsquo;t support the various packets well with the current version of the fuzzer and grammar. Having this visualization is enormously helpful and necessary to succeed, as it is a source of truth about your fuzz target. By directing development work around these reports, it&rsquo;s relatively easy to plan actionable and high-value tasks around the fuzzer.</span></p> <p class="c11"><span>I like to think about improving a fuzz target by either improving &ldquo;soundness&rdquo; or &ldquo;completeness.&rdquo; Logicians probably wouldn&rsquo;t be happy with how I&rsquo;m loosely using these terms, but they are a good metaphor for the task. To start with, we can improve the completeness of a given fuzz target by helping it reach code that we know to be reachable based on manual review. In the above example, I would suspect very strongly that the uncovered option handling code is reachable. But despite a long fuzzing campaign, these lines are uncovered, and therefore our fuzz target is incomplete, somehow unable to generate inputs reaching these lines. There are two ways to get this needed coverage: in a top-down or bottom-up fashion. Each has its tradeoffs. The top-down way to cover this code is to improve the existing grammar or C++ code to make it possible or more likely. The bottom-up way is to modify the code in question. For example, we could replace </span><span class="c9">switch (opt)</span><span>&nbsp;with something like </span><span class="c9">switch (global_fuzzed_data-&gt;ConsumeRandomEnum(valid_enums)</span><span class="c8 c2">. This bottom-up approach introduces unsoundness, as maybe these enums could never have been selected at this point. But this approach has often led to interesting-looking crashes that encouraged me to revert the change and proceed with the more expensive top-down implementation. When it&rsquo;s one researcher working against potentially hundreds of thousands of lines, you need tricks to prioritize your work. By placing many cheap bets, you can revert later for free and focus on the most fruitful areas.</span></p> <p class="c11"><span class="c8 c2">Improving soundness is the other side of the coin here. I&rsquo;ve just mentioned reverting unsound changes and moving those changes out of the target code and into the grammar. But our fake objects are also simple models for how their real implementations behave. If those models are too simple or directly inaccurate, we may either miss bugs or introduce them. I&rsquo;m comfortable missing some bugs as I think these simple fakes enable better coverage, and it&rsquo;s a net win. But sometimes, I&rsquo;ll observe a crash or failure to cover some code because of a faulty model. So improvements can often come in the form of making these fakes better.</span></p> <p class="c11"><span class="c8 c2">All in all, there is plenty of work that can be done at any given point. Fuzzing isn&rsquo;t an all or nothing one-shot endeavor for large targets like this. This is a continuous process, and as time goes on, easy gains become harder to achieve as most bugs detectable with this approach are found, and eventually, there comes a natural stopping point. But despite working on this project for several months, it&rsquo;s remarkably far from the finish line despite producing several useful bug reports. The cool thing about fuzzing in this way is that it is a bit like excavating a fossil. Each target is different; we make small changes to the fuzzer, tapping away at the target with a chisel each day and letting our coverage metrics, not our biases, reveal the path forward.</span></p><h1 class="c26 c23" id="h.rxgvq2murgo6"><span class="c27 c2">Packet Delivery</span></h1> <p class="c11"><span class="c8 c2">I&rsquo;d like to cover one example to demonstrate the value of the &ldquo;bottom-up&rdquo; unsound modification, as in some cases, the unsound modification is dramatically cheaper than the grammar-based one. Disabling hash checks is a well-known fuzzer-only modification when fuzzer-authors know that checksums could be trivially generated by hand. But it can also be applied in other places, such as packet delivery.</span></p> <p class="c11"><span>When an mbuf containing a TCP packet arrives, it is handled by </span><span class="c9">tcp_input</span><span class="c8 c2">. In order for almost anything meaningful to occur with this packet, it must be matched by IP address and port to an existing process control block (PCB) for that connection, as seen below.</span></p><a id="t.59f43b4f2ff0c1f12bb616ac7f9a7c91aabcf10b"></a><a id="t.26"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">void</span></p> <p class="c4"><span class="c0">tcp_input</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;mbuf </span><span class="c1">*</span><span class="c0">m</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">int</span><span class="c0">&nbsp;off0</span><span class="c1">)</span></p> <p class="c4"><span class="c1">{</span></p> <p class="c4"><span class="c17">// ...</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">isipv6</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inp </span><span class="c1">=</span><span class="c0">&nbsp;in6_pcblookup_hash</span><span class="c1">(&amp;</span><span class="c0">tcbinfo</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">ip6</span><span class="c1">-&gt;</span><span class="c0">ip6_src</span><span class="c1">,</span><span class="c0">&nbsp;th</span><span class="c1">-&gt;</span><span class="c0">th_sport</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">&amp;</span><span class="c0">ip6</span><span class="c1">-&gt;</span><span class="c0">ip6_dst</span><span class="c1">,</span><span class="c0">&nbsp;th</span><span class="c1">-&gt;</span><span class="c0">th_dport</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; m</span><span class="c1">-&gt;</span><span class="c0">m_pkthdr</span><span class="c1">.</span><span class="c0">rcvif</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span><span class="c0">&nbsp;</span><span class="c6">else</span></p> <p class="c4"><span class="c17">#endif</span><span class="c0">&nbsp;</span><span class="c17">/* INET6 */</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; inp </span><span class="c1">=</span><span class="c0">&nbsp;in_pcblookup_hash</span><span class="c1">(&amp;</span><span class="c0">tcbinfo</span><span class="c1">,</span><span class="c0">&nbsp;ip</span><span class="c1">-&gt;</span><span class="c0">ip_src</span><span class="c1">,</span><span class="c0">&nbsp;th</span><span class="c1">-&gt;</span><span class="c0">th_sport</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip</span><span class="c1">-&gt;</span><span class="c0">ip_dst</span><span class="c1">,</span><span class="c0">&nbsp;th</span><span class="c1">-&gt;</span><span class="c0">th_dport</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">,</span><span class="c0">&nbsp;m</span><span class="c1">-&gt;</span><span class="c0">m_pkthdr</span><span class="c1">.</span><span class="c0">rcvif</span><span class="c1">);</span></p></td></tr></tbody></table> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c11"><span>Here&rsquo;s the IPv4 lookup code. Note that </span><span class="c9">faddr</span><span>, </span><span class="c9">fport_arg</span><span>, </span><span class="c9">laddr</span><span>, and </span><span class="c9">lport_arg</span><span>&nbsp;are all taken directly from the packet and are checked against the list of PCBs, one at a time. This means that we must guess two 4-byte integers and two 2-byte shorts to match the packet to the relevant PCB. Even coverage-guided fuzzing is going to have a hard time guessing its way through these comparisons. While eventually a match will be found, we can radically improve the odds of covering meaningful code by just flipping a coin instead of doing the comparisons. This change is extremely easy to make, as we can fetch a random boolean from the fuzzer at runtime. Looking up existing PCBs and fixing up the IP/TCP headers before sending the packets is a sounder solution, but in my testing this change didn&rsquo;t introduce any regressions. Now when a vulnerability is discovered, it&rsquo;s just a matter of fixing up headers to match packets to the appropriate PCB. That&rsquo;s light work for a vulnerability researcher looking for a remote memory corruption bug.</span></p><a id="t.927b886dd5a32d7f9b647faf078857d678f6d1bf"></a><a id="t.27"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c17">/*</span></p> <p class="c4"><span class="c17">&nbsp;* Lookup PCB in hash list.</span></p> <p class="c4"><span class="c17">&nbsp;*/</span></p> <p class="c4"><span class="c6">struct</span><span class="c0">&nbsp;inpcb </span><span class="c1">*</span></p> <p class="c4"><span class="c0">in_pcblookup_hash</span><span class="c1">(</span><span class="c6">struct</span><span class="c0">&nbsp;inpcbinfo </span><span class="c1">*</span><span class="c0">pcbinfo</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">struct</span><span class="c0">&nbsp;in_addr faddr</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; u_int fport_arg</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">struct</span><span class="c0">&nbsp;in_addr laddr</span><span class="c1">,</span><span class="c0">&nbsp;u_int lport_arg</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">int</span><span class="c0">&nbsp;wildcard</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">struct</span><span class="c0">&nbsp;ifnet </span><span class="c1">*</span><span class="c0">ifp</span><span class="c1">)</span></p> <p class="c4"><span class="c1">{</span></p> <p class="c4"><span class="c17">// ...</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; head </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">pcbinfo</span><span class="c1">-&gt;</span><span class="c0">ipi_hashbase</span><span class="c1">[</span><span class="c0">INP_PCBHASH</span><span class="c1">(</span><span class="c0">faddr</span><span class="c1">.</span><span class="c0">s_addr</span><span class="c1">,</span><span class="c0">&nbsp;lport</span><span class="c1">,</span><span class="c0">&nbsp;fport</span><span class="c1">,</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; pcbinfo</span><span class="c1">-&gt;</span><span class="c0">ipi_hashmask</span><span class="c1">)];</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; LIST_FOREACH</span><span class="c1">(</span><span class="c0">inp</span><span class="c1">,</span><span class="c0">&nbsp;head</span><span class="c1">,</span><span class="c0">&nbsp;inp_hash</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c1">-</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">inp</span><span class="c1">-&gt;</span><span class="c0">inp_faddr</span><span class="c1">.</span><span class="c0">s_addr </span><span class="c1">==</span><span class="c0">&nbsp;faddr</span><span class="c1">.</span><span class="c0">s_addr </span><span class="c1">&amp;&amp;</span></p> <p class="c4"><span class="c1">-</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inp</span><span class="c1">-&gt;</span><span class="c0">inp_laddr</span><span class="c1">.</span><span class="c0">s_addr </span><span class="c1">==</span><span class="c0">&nbsp;laddr</span><span class="c1">.</span><span class="c0">s_addr </span><span class="c1">&amp;&amp;</span></p> <p class="c4"><span class="c1">-</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inp</span><span class="c1">-&gt;</span><span class="c0">inp_fport </span><span class="c1">==</span><span class="c0">&nbsp;fport </span><span class="c1">&amp;&amp;</span></p> <p class="c4"><span class="c1">-</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; inp</span><span class="c1">-&gt;</span><span class="c0">inp_lport </span><span class="c1">==</span><span class="c0">&nbsp;lport</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c1">+</span><span class="c0">&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(!</span><span class="c0">get_fuzzed_bool</span><span class="c1">())</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">in_pcb_checkstate</span><span class="c1">(</span><span class="c0">inp</span><span class="c1">,</span><span class="c0">&nbsp;WNT_ACQUIRE</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">!=</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; WNT_STOPUSING</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; lck_rw_done</span><span class="c1">(</span><span class="c0">pcbinfo</span><span class="c1">-&gt;</span><span class="c0">ipi_lock</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;inp</span><span class="c1">;</span></p></td></tr></tbody></table> <p class="c11"><span class="c8 c2"><br>Astute readers may have noticed that the PCBs are fetched from a hash table, so it&rsquo;s not enough just to replace the check. The 4 values used in the linear search are used to calculate a PCB hash, so we have to make sure all PCBs share a single bucket, as seen in the diff below. The real kernel shouldn&rsquo;t do this as lookups become O(n), but we only create a few sockets, so it&rsquo;s acceptable.</span></p><a id="t.ff85c5d49936d74a427dd2c77dc5b4f6949346c9"></a><a id="t.28"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">diff </span><span class="c1">--</span><span class="c0">git a</span><span class="c1">/</span><span class="c0">bsd</span><span class="c1">/</span><span class="c0">netinet</span><span class="c1">/</span><span class="c0">in_pcb</span><span class="c1">.</span><span class="c0">h b</span><span class="c1">/</span><span class="c0">bsd</span><span class="c1">/</span><span class="c0">netinet</span><span class="c1">/</span><span class="c0">in_pcb</span><span class="c1">.</span><span class="c0 c2">h</span></p> <p class="c4"><span class="c0">index a5ec42ab</span><span class="c1">..</span><span class="c3">37f6ee50</span><span class="c0">&nbsp;</span><span class="c3">100644</span></p> <p class="c4"><span class="c1">---</span><span class="c0">&nbsp;a</span><span class="c1">/</span><span class="c0">bsd</span><span class="c1">/</span><span class="c0">netinet</span><span class="c1">/</span><span class="c0">in_pcb</span><span class="c1">.</span><span class="c0 c2">h</span></p> <p class="c4"><span class="c1">+++</span><span class="c0">&nbsp;b</span><span class="c1">/</span><span class="c0">bsd</span><span class="c1">/</span><span class="c0">netinet</span><span class="c1">/</span><span class="c0">in_pcb</span><span class="c1">.</span><span class="c0 c2">h</span></p> <p class="c4"><span class="c1">@@</span><span class="c0">&nbsp;</span><span class="c1">-</span><span class="c3">611</span><span class="c1">,</span><span class="c3">10</span><span class="c0">&nbsp;</span><span class="c1">+</span><span class="c3">611</span><span class="c1">,</span><span class="c3">9</span><span class="c0">&nbsp;</span><span class="c1">@@</span><span class="c0">&nbsp;</span><span class="c6">struct</span><span class="c0">&nbsp;inpcbinfo </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; u_int32_t &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ipi_flags</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp;</span><span class="c1">};</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c1">-</span><span class="c17">#define</span><span class="c0">&nbsp;INP_PCBHASH</span><span class="c1">(</span><span class="c0">faddr</span><span class="c1">,</span><span class="c0">&nbsp;lport</span><span class="c1">,</span><span class="c0">&nbsp;fport</span><span class="c1">,</span><span class="c0">&nbsp;mask</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">\</span></p> <p class="c4"><span class="c1">-</span><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c1">(((</span><span class="c0">faddr</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">^</span><span class="c0">&nbsp;</span><span class="c1">((</span><span class="c0">faddr</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">&gt;&gt;</span><span class="c0">&nbsp;</span><span class="c3">16</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">^</span><span class="c0">&nbsp;ntohs</span><span class="c1">((</span><span class="c0">lport</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">^</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">fport</span><span class="c1">)))</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">mask</span><span class="c1">))</span></p> <p class="c4"><span class="c1">-</span><span class="c17">#define</span><span class="c0">&nbsp;INP_PCBPORTHASH</span><span class="c1">(</span><span class="c0">lport</span><span class="c1">,</span><span class="c0">&nbsp;mask</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">\</span></p> <p class="c4"><span class="c1">-</span><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp;</span><span class="c1">(</span><span class="c0">ntohs</span><span class="c1">((</span><span class="c0">lport</span><span class="c1">))</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">mask</span><span class="c1">))</span></p> <p class="c4"><span class="c1">+</span><span class="c17">// nedwill: let all pcbs share the same hash</span></p> <p class="c4"><span class="c1">+</span><span class="c17">#define</span><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; INP_PCBHASH</span><span class="c1">(</span><span class="c0">faddr</span><span class="c1">,</span><span class="c0">&nbsp;lport</span><span class="c1">,</span><span class="c0">&nbsp;fport</span><span class="c1">,</span><span class="c0">&nbsp;mask</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c3">0</span><span class="c1">)</span></p> <p class="c4"><span class="c1">+</span><span class="c17">#define</span><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; INP_PCBPORTHASH</span><span class="c1">(</span><span class="c0">lport</span><span class="c1">,</span><span class="c0">&nbsp;mask</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c3">0</span><span class="c1">)</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp;</span><span class="c17">#define</span><span class="c0">&nbsp;INP_IS_FLOW_CONTROLLED</span><span class="c1">(</span><span class="c0">_inp_</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">\</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">((</span><span class="c0">_inp_</span><span class="c1">)-&gt;</span><span class="c0">inp_flags </span><span class="c1">&amp;</span><span class="c0">&nbsp;INP_FLOW_CONTROLLED</span><span class="c1">)</span></p></td></tr></tbody></table> <p class="c11 c15"><span class="c8 c2"></span></p> <p class="c11 c23 title" id="h.14k82770mpb"><span class="c7 c2">Checking Our Work: Reproducing the Sample Bugs</span></p> <p class="c4 c18"><span class="c8 c2">With most of the necessary supporting code implemented, we can fuzz for a while without hitting any assertions due to unimplemented stubbed functions. At this stage, I reverted the fixes for the two inspiration bugs I mentioned at the beginning of this article. Here&rsquo;s what we see shortly after we run the fuzzer with those fixes reverted:<br></span></p><a id="t.b2722f59e62293fbbc44bd59d6442b0f062757f2"></a><a id="t.29"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c1">==</span><span class="c3">1633983</span><span class="c1">==</span><span class="c0">ERROR</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c13">AddressSanitizer</span><span class="c1">:</span><span class="c0">&nbsp;heap</span><span class="c1">-</span><span class="c0">buffer</span><span class="c1">-</span><span class="c0">overflow on address </span><span class="c3">0x61d00029f474</span><span class="c0">&nbsp;at pc </span><span class="c3">0x00000049fcb7</span><span class="c0">&nbsp;bp </span><span class="c3">0x7ffcddc88590</span><span class="c0">&nbsp;sp </span><span class="c3">0x7ffcddc87d58</span></p> <p class="c4"><span class="c0">WRITE of size </span><span class="c3">20</span><span class="c0">&nbsp;at </span><span class="c3">0x61d00029f474</span><span class="c0 c2">&nbsp;thread T0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#0 0x49fcb6 in __asan_memmove /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp:30:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#1 0x7ff64bd83bd9 in __asan_bcopy fuzz/san.c:37:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#2 0x7ff64ba9e62f in icmp_error bsd/netinet/ip_icmp.c:362:2</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#3 0x7ff64baaff9b in ip_dooptions bsd/netinet/ip_input.c:3577:2</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#4 0x7ff64baa921b in ip_input bsd/netinet/ip_input.c:2230:34</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#5 0x7ff64bd7d440 in ip_input_wrapper fuzz/backend.c:132:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x4dbe29 in DoIpInput fuzz/net_fuzzer.cc:610:7</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#7 0x4de0ef in TestOneProtoInput(Session const&amp;) fuzz/net_fuzzer.cc:720:9</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c3">0x61d00029f474</span><span class="c0">&nbsp;</span><span class="c6">is</span><span class="c0">&nbsp;located </span><span class="c3">12</span><span class="c0">&nbsp;bytes to the left of </span><span class="c3">2048</span><span class="c1">-</span><span class="c6">byte</span><span class="c0">&nbsp;region </span><span class="c1">[</span><span class="c3">0x61d00029f480</span><span class="c1">,</span><span class="c3">0x61d00029fc80</span><span class="c1">)</span></p> <p class="c4"><span class="c0">allocated </span><span class="c6">by</span><span class="c0">&nbsp;thread T0 here</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#0 0x4a0479 in calloc /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:154:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#1 0x7ff64bd82b20 in mbuf_create fuzz/zalloc.c:157:45</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#2 0x7ff64bd8319e in mcache_alloc fuzz/zalloc.c:187:12</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#3 0x7ff64b69ae84 in m_getcl bsd/kern/uipc_mbuf.c:3962:6</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#4 0x7ff64ba9e15c in icmp_error bsd/netinet/ip_icmp.c:296:7</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#5 0x7ff64baaff9b in ip_dooptions bsd/netinet/ip_input.c:3577:2</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x7ff64baa921b in ip_input bsd/netinet/ip_input.c:2230:34</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#7 0x7ff64bd7d440 in ip_input_wrapper fuzz/backend.c:132:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#8 0x4dbe29 in DoIpInput fuzz/net_fuzzer.cc:610:7</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#9 0x4de0ef in TestOneProtoInput(Session const&amp;) fuzz/net_fuzzer.cc:720:9</span></p></td></tr></tbody></table> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span>When we inspect the test case, we see that a single raw IPv4 packet was generated to trigger this bug. This is to be expected, as the bug doesn&rsquo;t require an existing connection, and looking at the stack, we can see that the test case triggered the bug in the IPv4-specific </span><span class="c9">ip_input</span><span class="c8 c2">&nbsp;path.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p><a id="t.e5f0cef3123c406738ed1868e0c2fa3f334081f3"></a><a id="t.30"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; ip_input </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; raw_ip4</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;M\001\000I\001\000\000\000\000\000\000\000III\333\333\333\333\333\333\333\333\333\333IIIIIIIIIIIIII\000\000\000\000\000III\333\333\333\333\333\333\333\333\333\333\333\333IIIIIIIIIIIIII&quot;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">data_provider</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;&quot;</span></p></td></tr></tbody></table> <p class="c11"><span><br>If we fix that issue and fuzz a bit longer, we soon see another crash, this time in the MPTCP stack. This is Ian&rsquo;s MPTCP vulnerability. The ASAN report looks strange though. Why is it crashing during garbage collection in </span><span class="c9">mptcp_session_destroy</span><span class="c8 c2">? The original vulnerability was an OOB write, but ASAN couldn&rsquo;t catch it because it corrupted memory within a struct. This is a well-known shortcoming of ASAN and similar mitigations, importantly the upcoming MTE. This means we don&rsquo;t catch the bug until later, when a randomly corrupted pointer is accessed.</span></p><a id="t.38f4e091ebe11281f4c9363d7093c9f69ad01412"></a><a id="t.31"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c1">==</span><span class="c3">1640571</span><span class="c1">==</span><span class="c0">ERROR</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c13">AddressSanitizer</span><span class="c1">:</span><span class="c0">&nbsp;attempting free on address which was </span><span class="c6">not</span><span class="c0">&nbsp;malloc</span><span class="c1">()-</span><span class="c0">ed</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0x6190000079dc</span><span class="c0">&nbsp;</span><span class="c6">in</span><span class="c0 c2">&nbsp;thread T0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#0 0x4a0094 in free /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:123:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#1 0x7fbdfc7a16b0 in _FREE fuzz/zalloc.c:293:36</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#2 0x7fbdfc52b624 in mptcp_session_destroy bsd/netinet/mptcp_subr.c:742:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#3 0x7fbdfc50c419 in mptcp_gc bsd/netinet/mptcp_subr.c:4615:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#4 0x7fbdfc4ee052 in mp_timeout bsd/netinet/mp_pcb.c:118:16</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#5 0x7fbdfc79b232 in clear_all fuzz/backend.c:83:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x4dfd5c in TestOneProtoInput(Session const&amp;) fuzz/net_fuzzer.cc:1010:3</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c3">0x6190000079dc</span><span class="c0">&nbsp;</span><span class="c6">is</span><span class="c0">&nbsp;located </span><span class="c3">348</span><span class="c0">&nbsp;bytes inside of </span><span class="c3">920</span><span class="c1">-</span><span class="c6">byte</span><span class="c0">&nbsp;region </span><span class="c1">[</span><span class="c3">0x619000007880</span><span class="c1">,</span><span class="c3">0x619000007c18</span><span class="c1">)</span></p> <p class="c4"><span class="c0">allocated </span><span class="c6">by</span><span class="c0">&nbsp;thread T0 here</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#0 0x4a0479 in calloc /b/s/w/ir/cache/builder/src/third_party/llvm/compiler-rt/lib/asan/asan_malloc_linux.cpp:154:3</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#1 0x7fbdfc7a03d4 in zalloc fuzz/zalloc.c:37:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#2 0x7fbdfc4ee710 in mp_pcballoc bsd/netinet/mp_pcb.c:222:8</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#3 0x7fbdfc53cf8a in mptcp_attach bsd/netinet/mptcp_usrreq.c:211:15</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#4 0x7fbdfc53699e in mptcp_usr_attach bsd/netinet/mptcp_usrreq.c:128:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#5 0x7fbdfc0e1647 in socreate_internal bsd/kern/uipc_socket.c:784:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#6 0x7fbdfc0e23a4 in socreate bsd/kern/uipc_socket.c:871:9</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#7 0x7fbdfc118695 in socket_common bsd/kern/uipc_syscalls.c:266:11</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#8 0x7fbdfc1182d1 in socket bsd/kern/uipc_syscalls.c:214:9</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#9 0x7fbdfc79a26e in socket_wrapper fuzz/syscall_wrappers.c:371:10</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">#10 0x4dd275 in TestOneProtoInput(Session const&amp;) fuzz/net_fuzzer.cc:655:19</span></p></td></tr></tbody></table> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c11"><span>Here&rsquo;s the protobuf input for the crashing testcase:</span></p><a id="t.f691b70570e755735734b5e1a4200a505811568b"></a><a id="t.32"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; socket </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; domain</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; so_type</span><span class="c1">:</span><span class="c0 c2">&nbsp;SOCK_STREAM</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; protocol</span><span class="c1">:</span><span class="c0 c2">&nbsp;IPPROTO_IP</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; connectx </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; socket</span><span class="c1">:</span><span class="c0 c2">&nbsp;FD_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; endpoints </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_srcif</span><span class="c1">:</span><span class="c0 c2">&nbsp;IFIDX_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_srcaddr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sockaddr_generic </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_family</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\304&quot;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_dstaddr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sockaddr_generic </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_family</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;&quot;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; associd</span><span class="c1">:</span><span class="c0 c2">&nbsp;ASSOCID_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_IDEMPOTENT</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_IDEMPOTENT</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_IDEMPOTENT</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; connectx </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; socket</span><span class="c1">:</span><span class="c0 c2">&nbsp;FD_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; endpoints </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_srcif</span><span class="c1">:</span><span class="c0 c2">&nbsp;IFIDX_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_dstaddr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sockaddr_generic </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_family</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;&quot;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; associd</span><span class="c1">:</span><span class="c0 c2">&nbsp;ASSOCID_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_IDEMPOTENT</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; connectx </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; socket</span><span class="c1">:</span><span class="c0 c2">&nbsp;FD_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; endpoints </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_srcif</span><span class="c1">:</span><span class="c0 c2">&nbsp;IFIDX_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_srcaddr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sockaddr_generic </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_family</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;&quot;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_dstaddr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sockaddr_generic </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_family</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\304&quot;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; associd</span><span class="c1">:</span><span class="c0 c2">&nbsp;ASSOCID_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_IDEMPOTENT</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_IDEMPOTENT</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_AUTHENTICATED</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; connectx </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; socket</span><span class="c1">:</span><span class="c0 c2">&nbsp;FD_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; endpoints </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_srcif</span><span class="c1">:</span><span class="c0 c2">&nbsp;IFIDX_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_dstaddr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sockaddr_generic </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_family</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;&quot;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; associd</span><span class="c1">:</span><span class="c0 c2">&nbsp;ASSOCID_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;CONNECT_DATA_IDEMPOTENT</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; close </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; fd</span><span class="c1">:</span><span class="c0 c2">&nbsp;FD_8</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; ioctl_real </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; siocsifflags </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; ifr_name</span><span class="c1">:</span><span class="c0 c2">&nbsp;LO0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; flags</span><span class="c1">:</span><span class="c0 c2">&nbsp;IFF_LINK1</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; close </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; fd</span><span class="c1">:</span><span class="c0 c2">&nbsp;FD_8</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">data_provider</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025\025&quot;</span></p></td></tr></tbody></table> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c11"><span>Hmm, that&rsquo;s quite large and hard to follow. Is the bug really that complicated? We can use libFuzzer&rsquo;s crash minimization feature to find out. Protobuf-based test cases simplify nicely because even large test cases are already structured, so we can randomly edit and remove nodes from the message. After about a minute of automated minimization, we end up with the test shown below.</span></p><a id="t.9fd2c563e2b8930f35bbddc2b12b872cadc2745a"></a><a id="t.33"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; socket </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; domain</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; so_type</span><span class="c1">:</span><span class="c0 c2">&nbsp;SOCK_STREAM</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; protocol</span><span class="c1">:</span><span class="c0 c2">&nbsp;IPPROTO_IP</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; connectx </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; socket</span><span class="c1">:</span><span class="c0 c2">&nbsp;FD_0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; endpoints </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_srcif</span><span class="c1">:</span><span class="c0 c2">&nbsp;IFIDX_CASE_1</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; sae_dstaddr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sockaddr_generic </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_family</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_MULTIPATH</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; sa_data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;bugmbuf_debutoeloListen_dedeloListen_dedebuloListete_debugmbuf_debutoeloListen_dedeloListen_dedebuloListeListen_dedebuloListe_dtrte&quot;</span><span class="c0">&nbsp;</span><span class="c17"># string length 131</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; associd</span><span class="c1">:</span><span class="c0 c2">&nbsp;ASSOCID_CASE_0</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">data_provider</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;&quot;</span></p></td></tr></tbody></table> <p class="c11"><span><br>This is a lot easier to read! It appears that SockFuzzer managed to open a socket from the </span><span class="c9">AF_MULTIPATH</span><span>&nbsp;domain and called </span><span class="c9">connectx</span><span>&nbsp;on it with a sockaddr using an unexpected </span><span class="c9">sa_family</span><span>, in this case </span><span class="c9">AF_MULTIPATH</span><span>. Then the large </span><span class="c9">sa_data</span><span class="c8 c2">&nbsp;field was used to overwrite memory. You can see some artifacts of heuristics used by the fuzzer to guess strings as &ldquo;listen&rdquo; and &ldquo;mbuf&rdquo; appear in the input. This testcase could be further simplified by modifying the sa_data to a repeated character, but I left it as is so you can see exactly what it&rsquo;s like to work with the output of this fuzzer.</span></p> <p class="c11"><span>In my experience, t</span><span class="c8 c2">he protobuf-formatted syscalls and packet descriptions were highly useful for reproducing crashes and tended to work on the first attempt. I didn&rsquo;t have an excellent setup for debugging on-device, so I tried to lean on the fuzzing framework as much as I could to understand issues before proceeding with the expensive process of reproducing them.</span></p> <p class="c11"><span>In </span><span class="c14"><a class="c121" href="https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html">my </a></span><span class="c14"><a class="c121" href="https://googleprojectzero.blogspot.com/2019/12/sockpuppet-walkthrough-of-kernel.html">previous post</a></span><span>&nbsp;describing the &ldquo;SockPuppet&rdquo; vulnerability</span><span>, I walked through one of the newly discovered vulnerabilities, from protobuf to exploit. I&rsquo;d like to share another original protobuf bug report for a remotely-triggered vulnerability I reported </span><span class="c14"><a class="c121" href="https://bugs.chromium.org/p/project-zero/issues/detail?id=1976">here</a></span><span class="c8 c2">.</span></p><a id="t.eac5bf4a152226018135f44cd838ea6f45dde5ec"></a><a id="t.34"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; socket </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; domain</span><span class="c1">:</span><span class="c0 c2">&nbsp;AF_INET6</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; so_type</span><span class="c1">:</span><span class="c0 c2">&nbsp;SOCK_RAW</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; protocol</span><span class="c1">:</span><span class="c0 c2">&nbsp;IPPROTO_IP</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; set_sock_opt </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; level</span><span class="c1">:</span><span class="c0 c2">&nbsp;SOL_SOCKET</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; name</span><span class="c1">:</span><span class="c0 c2">&nbsp;SO_RCVBUF</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; val</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;\021\000\000\000&quot;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; set_sock_opt </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; level</span><span class="c1">:</span><span class="c0 c2">&nbsp;IPPROTO_IPV6</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; name</span><span class="c1">:</span><span class="c0 c2">&nbsp;IP_FW_ZERO</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; val</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;\377\377\377\377&quot;</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">commands </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; ip_input </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; tcp6_packet </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; ip6_hdr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; ip6_hdrctl </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip6_un1_flow</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip6_un1_plen</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip6_un1_nxt</span><span class="c1">:</span><span class="c0 c2">&nbsp;IPPROTO_ICMPV6</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ip6_un1_hlim</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; ip6_src</span><span class="c1">:</span><span class="c0 c2">&nbsp;IN6_ADDR_LOOPBACK</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; ip6_dst</span><span class="c1">:</span><span class="c0 c2">&nbsp;IN6_ADDR_ANY</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; tcp_hdr </span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_sport</span><span class="c1">:</span><span class="c0 c2">&nbsp;PORT_2</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_dport</span><span class="c1">:</span><span class="c0 c2">&nbsp;PORT_1</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_seq</span><span class="c1">:</span><span class="c0 c2">&nbsp;SEQ_1</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_ack</span><span class="c1">:</span><span class="c0 c2">&nbsp;SEQ_1</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_off</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_win</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_sum</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; th_urp</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c3">0</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; is_pure_syn</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c6">false</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; is_pure_ack</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c6">false</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; data</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;\377\377\377\377\377\377\377\377\377\377\377\377q\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377\377&quot;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c1">}</span></p> <p class="c4"><span class="c0">data_provider</span><span class="c1">:</span><span class="c0">&nbsp;</span><span class="c19">&quot;&quot;</span></p></td></tr></tbody></table> <p class="c11 c15"><span class="c8 c2"></span></p> <p class="c11"><span class="c8 c2">This automatically minimized test case requires some human translation to a report that&rsquo;s actionable by developers who don&rsquo;t have access to our fuzzing framework. The test creates a socket and sets some options before delivering a crafted ICMPv6 packet. You can see how the packet grammar we specified comes in handy. I started by transcribing the first three syscall messages directly by writing the following C program.</span></p><a id="t.c9d8fb90175071c7e24d3ed9cb5e3b8cad7693a3"></a><a id="t.35"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c17">#include</span><span class="c0">&nbsp;</span><span class="c19">&lt;sys/socket.h&gt;</span></p> <p class="c4"><span class="c17">#define</span><span class="c0 c2">&nbsp;__APPLE_USE_RFC_3542</span></p> <p class="c4"><span class="c17">#include</span><span class="c0">&nbsp;</span><span class="c19">&lt;netinet/in.h&gt;</span></p> <p class="c4"><span class="c17">#include</span><span class="c0">&nbsp;</span><span class="c19">&lt;stdio.h&gt;</span></p> <p class="c4"><span class="c17">#include</span><span class="c0">&nbsp;</span><span class="c19">&lt;unistd.h&gt;</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">int</span><span class="c0">&nbsp;main</span><span class="c1">()</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;fd </span><span class="c1">=</span><span class="c0">&nbsp;socket</span><span class="c1">(</span><span class="c0">AF_INET6</span><span class="c1">,</span><span class="c0">&nbsp;SOCK_RAW</span><span class="c1">,</span><span class="c0">&nbsp;IPPROTO_IP</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">if</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c0">fd </span><span class="c1">&lt;</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; printf</span><span class="c1">(</span><span class="c19">&quot;failed\n&quot;</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;res</span><span class="c1">;</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">// This is not needed to cause a crash on macOS 10.14.6, but you can</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">// try setting this option if you can&#39;t reproduce the issue.</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">// int space = 1;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">// res = setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &amp;space, sizeof(space));</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">// printf(&quot;res1: %d\n&quot;, res);</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">int</span><span class="c0">&nbsp;enable </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c3">1</span><span class="c1">;</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; res </span><span class="c1">=</span><span class="c0">&nbsp;setsockopt</span><span class="c1">(</span><span class="c0">fd</span><span class="c1">,</span><span class="c0">&nbsp;IPPROTO_IPV6</span><span class="c1">,</span><span class="c0">&nbsp;IPV6_RECVPATHMTU</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c1">&amp;</span><span class="c0">enable</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c6">sizeof</span><span class="c1">(</span><span class="c0">enable</span><span class="c1">));</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; printf</span><span class="c1">(</span><span class="c19">&quot;res2: %d\n&quot;</span><span class="c1">,</span><span class="c0">&nbsp;res</span><span class="c1">);</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c17">// Keep the socket open without terminating.</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">while</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c3">1</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">{</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; &nbsp; &nbsp; sleep</span><span class="c1">(</span><span class="c3">5</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c1">}</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; close</span><span class="c1">(</span><span class="c0">fd</span><span class="c1">);</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; </span><span class="c6">return</span><span class="c0">&nbsp;</span><span class="c3">0</span><span class="c1">;</span></p> <p class="c4"><span class="c1">}</span></p></td></tr></tbody></table> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4 c18"><span>With the socket open, it&rsquo;s now a matter of sending a special ICMPv6 packet to trigger the bug. Using the original crash as a guide, I reviewed the code around the crashing instruction to understand which parts of the input were relevant. I discovered that sending a &ldquo;packet too big&rdquo; notification would reach the buggy code, so I used the </span><span class="c14"><a class="c121" href="https://scapy.net/">scapy</a></span><span>&nbsp;library for Python to send the buggy packet locally. My kernel panicked, confirming the double free vulnerability.</span></p> <p class="c4 c15"><span class="c0 c2"></span></p><a id="t.5835bc8393a6afa2b0624af9b70d27f9f4b58fd4"></a><a id="t.36"></a><table class="c5"><tbody><tr class="c10"><td class="c16" colspan="1" rowspan="1"> <p class="c4"><span class="c6">from</span><span class="c0">&nbsp;scapy</span><span class="c1">.</span><span class="c0">all </span><span class="c6">import</span><span class="c0">&nbsp;sr1</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c13">IPv6</span><span class="c1">,</span><span class="c0">&nbsp;</span><span class="c13">ICMPv6PacketTooBig</span><span class="c1">,</span><span class="c0 c2">&nbsp;raw</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c0">outer </span><span class="c1">=</span><span class="c0">&nbsp;</span><span class="c13">IPv6</span><span class="c1">(</span><span class="c0">dst</span><span class="c1">=</span><span class="c19">&quot;::1&quot;</span><span class="c1">)</span><span class="c0">&nbsp;</span><span class="c1">/</span><span class="c0">&nbsp;</span><span class="c13">ICMPv6PacketTooBig</span><span class="c1">()</span><span class="c0">&nbsp;</span><span class="c1">/</span><span class="c0">&nbsp;</span><span class="c1">(</span><span class="c19">&quot;\x41&quot;</span><span class="c1">*</span><span class="c3">40</span><span class="c1">)</span></p> <p class="c4 c15"><span class="c0 c2"></span></p> <p class="c4"><span class="c6">print</span><span class="c1">(</span><span class="c0">raw</span><span class="c1">(</span><span class="c0">outer</span><span class="c1">).</span><span class="c0">hex</span><span class="c1">())</span></p> <p class="c4"><span class="c0">p </span><span class="c1">=</span><span class="c0">&nbsp;sr1</span><span class="c1">(</span><span class="c0">outer</span><span class="c1">)</span></p> <p class="c4"><span class="c6">if</span><span class="c0">&nbsp;p</span><span class="c1">:</span></p> <p class="c4"><span class="c0">&nbsp; &nbsp; p</span><span class="c1">.</span><span class="c0">show</span><span class="c1">()</span></p></td></tr></tbody></table> <p class="c11"><span class="c8 c2">Creating a working PoC from the crashing protobuf input took about an hour, thanks to the straightforward mapping from grammar to syscalls/network input and the utility of being able to debug the local crashing &ldquo;kernel&rdquo; using gdb.</span></p> <p class="c11 c23 title" id="h.3b7k7e45aqfc"><span class="c7 c2">Drawbacks</span></p> <p class="c11"><span>Any fuzzing project of this size will require design decisions that have some tradeoffs. The most obvious issue is the inability to detect race conditions. Threading bugs can be found with fuzzing but are still best left to static analysis and manual review as fuzzers can&rsquo;t currently deal with the state space of interleaving threads. Maybe this will change in the future, but today it&rsquo;s an issue. I accepted this problem and removed threading completely from the fuzzer; some bugs were missed by this, such as a race condition </span><span class="c14"><a class="c121" href="https://youtu.be/8cOx7vfszZU?t=366">in the bind syscall</a></span><span class="c8 c2">.</span></p> <p class="c11"><span>Another issue lies in the fact that by replacing so much functionality by hand, it&rsquo;s hard to extend the fuzzer trivially to support additional attack surfaces. This is evidenced by another issue I missed in </span><span class="c14"><a class="c121" href="https://twitter.com/WangTielei/status/1246376070367965184">packet filtering</a></span><span class="c8 c2">. I don&rsquo;t support VFS at the moment, so I can&rsquo;t access the bpf device. A syzkaller-like project would have less trouble with supporting this code since VFS would already be working. I made an explicit decision to build a simple tool that works very effectively and meticulously, but this can mean missing some low hanging fruit due to the effort involved.</span></p> <p class="c4 c18"><span class="c8 c2">Per-test case determinism is an issue that I&rsquo;ve solved only partially. If test cases aren&rsquo;t deterministic, libFuzzer becomes less efficient as it thinks some tests are finding new coverage when they really depend on one that was run previously. To mitigate this problem, I track open file descriptors manually and run all of the garbage collection thread functions after each test case. Unfortunately, there are many ioctls that change state in the background. It&rsquo;s hard to keep track of them to clean up properly but they are important enough that it&rsquo;s not worth disabling them just to improve determinism. If I were working on a long-term well-resourced overhaul of the XNU network stack, I would probably make sure there&rsquo;s a way to cleanly tear down the whole stack to prevent this problem.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c11"><span>Perhaps the largest caveat of this project is its reliance on source code. Without the efficiency and productivity losses that come with binary-only research, I can study the problem more closely to the source. But I humbly admit that this approach ignores many targets and doesn&rsquo;t necessarily match real attackers&rsquo; workflows. Real attackers take the shortest path they can to find an exploitable vulnerability, and often that path is through bugs found via binary-based fuzzing or reverse engineering and auditing. I intend to discover some of the best practices for fuzzing with the source and then migrate this approach to work with binaries. </span><span class="c14"><a class="c121" href="https://github.com/googleprojectzero/TinyInst">Binary instrumentation</a></span><span class="c8 c2">&nbsp;can assist in coverage guided fuzzing, but some of my tricks around substituting fake implementations or changing behavior to be more fuzz-friendly is a more significant burden when working with binaries. But I believe these are tractable problems, and I expect researchers can adapt some of these techniques to binary-only fuzzing efforts, even if there is additional overhead.</span></p> <p class="c11 c23 title" id="h.vb3z86pd31px"><span class="c7 c2">Open Sourcing and Future Work</span></p> <p class="c11"><span>This fuzzer is now open source on </span><span class="c14"><a class="c121" href="https://github.com/googleprojectzero/SockFuzzer">GitHub</a></span><span class="c8 c2">. I invite you to study the code and improve it! I&rsquo;d like to continue the development of this fuzzer semi-publicly. Some modifications that yield new vulnerabilities may need to be embargoed until relevant patches go out. Still, I hope that I can be as transparent as possible in my research. By working publicly, it may be possible to bring the original XNU project and this fuzzer closer together by sharing the efforts. I&rsquo;m hoping the upstream developers can make use of this project to perform their own testing and perhaps make their own improvements to XNU to make this type of testing more accessible. There&rsquo;s plenty of remaining work to improve the existing grammar, add support for new subsystems, and deal with some high-level design improvements such as adding proper threading support.</span></p> <p class="c11"><span class="c8 c2">An interesting property of the current fuzzer is that despite reaching coverage saturation on ClusterFuzz after many months, there is still reachable but uncovered code due to the enormous search space. This means that improvements in coverage-guided fuzzing could find new bugs. I&rsquo;d like to encourage teams who perform fuzzing engine research to use this project as a baseline. If you find a bug, you can take the credit for it! I simply hope you share your improvements with me and the rest of the community.</span></p> <p class="c18 c23 c25 title" id="h.n705fp4we09t"><span class="c7 c2">Conclusion</span></p> <p class="c4 c18"><span>Modern kernel development has some catching up to do. XNU and Linux suffer from some process failures that lead to </span><span class="c14"><a class="c121" href="https://www.synacktiv.com/en/publications/return-of-the-ios-sandbox-escape-lightspeeds-back-in-the-race.html">shipping</a></span><span>&nbsp;</span><span class="c14"><a class="c121" href="https://www.theguardian.com/technology/2019/aug/20/apple-reopens-security-flaw-ios-iphone">security</a></span><span>&nbsp;</span><span class="c14"><a class="c121" href="https://git.kernel.org/pub/scm/linux/kernel/git/netdev/net.git/commit/?id=c6c9fee35dc27362b7bac34b2fc9f5b8ace2e22c">regressions</a></span><span>. Kernels, perhaps the most security-critical component of operating systems, are becoming increasingly fragile as memory corruption issues become easier to discover. Implementing better mitigations is half the battle; we need better kernel unit testing to make identifying and fixing (even non-security) </span><span>bugs </span><span class="c8 c2">cheaper.</span></p> <p class="c4 c18 c15"><span class="c8 c2"></span></p> <p class="c4 c18"><span class="c8 c2">Since my last post, Apple has increased the frequency of its open-source releases. This is great for end-user security. The more publicly that Apple can develop XNU, the more that external contributors like myself may have a chance to contribute fixes and improvements directly. Maintaining internal branches for upcoming product launches while keeping most development open has helped Chromium and Android security, and I believe XNU&rsquo;s development could follow this model. As software engineering grows as a field, our experience has shown us that open, shared, and continuous development has a real impact on software quality and stability by improving developer productivity. If you don&rsquo;t invest in CI, unit testing, security reviews, and fuzzing, attackers may do that for you - and users pay the cost whether they recognize it or not.</span></p><div> <p class="c4 c18 c15"><span class="c8 c2"></span></p></div> <div style='clear: both;'></div> </div> <div class='post-footer'> <div class='post-footer-line post-footer-line-1'> <span class='post-author vcard'> Posted by <span class='fn' itemprop='author' itemscope='itemscope' itemtype='http://schema.org/Person'> <span itemprop='name'>Anonymous</span> </span> </span> <span class='post-timestamp'> at <meta content='https://googleprojectzero.blogspot.com/2021/04/designing-sockfuzzer-network-syscall.html' itemprop='url'/> <a class='timestamp-link' href='https://googleprojectzero.blogspot.com/2021/04/designing-sockfuzzer-network-syscall.html' rel='bookmark' title='permanent link'><abbr class='published' itemprop='datePublished' title='2021-04-22T11:05:00-07:00'>11:05&#8239;AM</abbr></a> </span> <span class='post-comment-link'> <a class='comment-link' href='https://googleprojectzero.blogspot.com/2021/04/designing-sockfuzzer-network-syscall.html#comment-form' onclick=''> No comments: </a> </span> <span class='post-icons'> <span class='item-control blog-admin pid-145400864'> <a href='https://www.blogger.com/post-edit.g?blogID=4838136820032157985&postID=2714099021755665939&from=pencil' title='Edit Post'> <img alt='' class='icon-action' height='18' src='https://resources.blogblog.com/img/icon18_edit_allbkg.gif' width='18'/> </a> </span> </span> <div class='post-share-buttons goog-inline-block'> <a class='goog-inline-block share-button sb-email' href='https://www.blogger.com/share-post.g?blogID=4838136820032157985&postID=2714099021755665939&target=email' target='_blank' title='Email This'><span class='share-button-link-text'>Email This</span></a><a class='goog-inline-block share-button sb-blog' href='https://www.blogger.com/share-post.g?blogID=4838136820032157985&postID=2714099021755665939&target=blog' onclick='window.open(this.href, "_blank", "height=270,width=475"); return false;' target='_blank' title='BlogThis!'><span class='share-button-link-text'>BlogThis!</span></a><a class='goog-inline-block share-button sb-twitter' href='https://www.blogger.com/share-post.g?blogID=4838136820032157985&postID=2714099021755665939&target=twitter' target='_blank' title='Share to X'><span class='share-button-link-text'>Share to X</span></a><a class='goog-inline-block share-button sb-facebook' href='https://www.blogger.com/share-post.g?blogID=4838136820032157985&postID=2714099021755665939&target=facebook' onclick='window.open(this.href, "_blank", "height=430,width=640"); return false;' target='_blank' title='Share to Facebook'><span class='share-button-link-text'>Share to Facebook</span></a><a class='goog-inline-block share-button sb-pinterest' href='https://www.blogger.com/share-post.g?blogID=4838136820032157985&postID=2714099021755665939&target=pinterest' target='_blank' title='Share to Pinterest'><span class='share-button-link-text'>Share to Pinterest</span></a> </div> </div> <div class='post-footer-line post-footer-line-2'> <span class='post-labels'> </span> </div> <div class='post-footer-line post-footer-line-3'> <span class='post-location'> </span> </div> </div> </div> </div> </div></div> </div> <div class='blog-pager' id='blog-pager'> <span id='blog-pager-newer-link'> <a class='blog-pager-newer-link' href='https://googleprojectzero.blogspot.com/search?updated-max=2021-06-29T08:58:00-07:00&amp;max-results=1&amp;reverse-paginate=true' id='Blog1_blog-pager-newer-link' title='Newer Posts'>Newer Posts</a> </span> <span id='blog-pager-older-link'> <a class='blog-pager-older-link' href='https://googleprojectzero.blogspot.com/search?updated-max=2021-04-22T11:05:00-07:00&amp;max-results=1' id='Blog1_blog-pager-older-link' title='Older Posts'>Older Posts</a> </span> <a class='home-link' href='https://googleprojectzero.blogspot.com/'>Home</a> </div> <div class='clear'></div> <div class='blog-feeds'> <div class='feed-links'> Subscribe to: <a class='feed-link' href='https://googleprojectzero.blogspot.com/feeds/posts/default' target='_blank' type='application/atom+xml'>Posts (Atom)</a> </div> </div> </div></div> </div> </div> <div class='column-left-outer'> <div class='column-left-inner'> <aside> </aside> </div> </div> <div class='column-right-outer'> <div class='column-right-inner'> <aside> <div class='sidebar section' id='sidebar-right-1'><div class='widget BlogSearch' data-version='1' id='BlogSearch1'> <h2 class='title'>Search This Blog</h2> <div class='widget-content'> <div id='BlogSearch1_form'> <form action='https://googleprojectzero.blogspot.com/search' class='gsc-search-box' target='_top'> <table cellpadding='0' cellspacing='0' class='gsc-search-box'> <tbody> <tr> <td class='gsc-input'> <input autocomplete='off' class='gsc-input' name='q' size='10' title='search' type='text' value=''/> </td> <td class='gsc-search-button'> <input class='gsc-search-button' title='search' type='submit' value='Search'/> </td> </tr> </tbody> </table> </form> </div> </div> <div class='clear'></div> </div><div class='widget PageList' data-version='1' id='PageList1'> <h2>Pages</h2> <div class='widget-content'> <ul> <li> <a href='https://googleprojectzero.blogspot.com/p/about-project-zero.html'>About Project Zero</a> </li> <li> <a href='https://googleprojectzero.blogspot.com/p/working-at-project-zero.html'>Working at Project Zero</a> </li> <li> <a href='https://googleprojectzero.blogspot.com/p/0day.html'>0day "In the Wild"</a> </li> <li> <a href='https://googleprojectzero.github.io/0days-in-the-wild/rca.html'>0day Exploit Root Cause Analyses</a> </li> <li> <a href='https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-faq.html'>Vulnerability Disclosure FAQ</a> </li> </ul> <div class='clear'></div> </div> </div><div class='widget BlogArchive' data-version='1' id='BlogArchive1'> <h2>Archives</h2> <div class='widget-content'> <div id='ArchiveList'> <div id='BlogArchive1_ArchiveList'> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2024/'> 2024 </a> <span class='post-count' dir='ltr'>(9)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2024/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2024/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2024/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2024/04/'> April </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/'> 2023 </a> <span class='post-count' dir='ltr'>(11)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/08/'> August </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2023/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/'> 2022 </a> <span class='post-count' dir='ltr'>(17)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/11/'> November </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2022/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/'> 2021 </a> <span class='post-count' dir='ltr'>(24)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate expanded'> <a class='toggle' href='javascript:void(0)'> <span class='zippy toggle-open'> &#9660;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> <ul class='posts'> <li><a href='https://googleprojectzero.blogspot.com/2021/04/designing-sockfuzzer-network-syscall.html'>Designing sockfuzzer, a network syscall fuzzer for...</a></li> <li><a href='https://googleprojectzero.blogspot.com/2021/04/policy-and-disclosure-2021-edition.html'>Policy and Disclosure: 2021 Edition</a></li> <li><a href='https://googleprojectzero.blogspot.com/2021/04/who-contains-containers.html'>Who Contains the Containers?</a></li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/02/'> February </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2021/01/'> January </a> <span class='post-count' dir='ltr'>(10)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/'> 2020 </a> <span class='post-count' dir='ltr'>(36)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/08/'> August </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/07/'> July </a> <span class='post-count' dir='ltr'>(8)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/06/'> June </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/02/'> February </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2020/01/'> January </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/'> 2019 </a> <span class='post-count' dir='ltr'>(27)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/08/'> August </a> <span class='post-count' dir='ltr'>(11)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/04/'> April </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2019/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/'> 2018 </a> <span class='post-count' dir='ltr'>(22)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/12/'> December </a> <span class='post-count' dir='ltr'>(7)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/10/'> October </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/08/'> August </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/06/'> June </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2018/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/'> 2017 </a> <span class='post-count' dir='ltr'>(19)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/10/'> October </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/04/'> April </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/03/'> March </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2017/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/'> 2016 </a> <span class='post-count' dir='ltr'>(17)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/11/'> November </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/09/'> September </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/08/'> August </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/07/'> July </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/06/'> June </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/03/'> March </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/02/'> February </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2016/01/'> January </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/'> 2015 </a> <span class='post-count' dir='ltr'>(33)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/12/'> December </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/10/'> October </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/09/'> September </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/08/'> August </a> <span class='post-count' dir='ltr'>(6)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/07/'> July </a> <span class='post-count' dir='ltr'>(5)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/06/'> June </a> <span class='post-count' dir='ltr'>(4)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/05/'> May </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/04/'> April </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/03/'> March </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/02/'> February </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2015/01/'> January </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2014/'> 2014 </a> <span class='post-count' dir='ltr'>(11)</span> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2014/12/'> December </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2014/11/'> November </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2014/10/'> October </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2014/09/'> September </a> <span class='post-count' dir='ltr'>(1)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2014/08/'> August </a> <span class='post-count' dir='ltr'>(2)</span> </li> </ul> <ul class='hierarchy'> <li class='archivedate collapsed'> <a class='toggle' href='javascript:void(0)'> <span class='zippy'> &#9658;&#160; </span> </a> <a class='post-count-link' href='https://googleprojectzero.blogspot.com/2014/07/'> July </a> <span class='post-count' dir='ltr'>(3)</span> </li> </ul> </li> </ul> </div> </div> <script type='text/javascript'> //<![CDATA[ (function(){ let archive_list = document.getElementById('ArchiveList'); if (archive_list == null) return; let cur_year = archive_list.querySelector('.post-count-link').innerText.trim() - 0; let last_year = 2014; let elements = []; const MONTHS = ',Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec'.split(','); let parent = document.getElementById('ArchiveList'); while (parent.childNodes.length) parent.removeChild(parent.childNodes[0]); function fetch_next_year() { let url = 'https://googleprojectzero.blogspot.com/?action=getTitles&widgetId=BlogArchive1&widgetType=BlogArchive&responseType=js&path=https%3A%2F%2Fgoogleprojectzero.blogspot.com%2F'+cur_year; fetch(url).then(resp => { if (!resp.ok) { console.log('http error'); return; } resp.text().then(text => { let scope = { _WidgetManager: { _HandleControllerResult: (name, method, results) => { elements.push(document.createElement('hr')); let year_header = document.createElement('div'); year_header.appendChild(document.createTextNode(cur_year)); year_header.style.fontSize = 'large'; elements.push(year_header); let list = document.createElement('ul'); elements.push(list); for (let obj of results.posts) { let link_parts = obj.url.split('/'); let year = link_parts[3]; let month = link_parts[4]; let el = document.createElement(/*'div'*/'li'); el.style.listStyleType = 'square'; el.style.listStylePosition = 'inside'; let link = document.createElement('a'); el.appendChild(link); link.appendChild(document.createTextNode(obj.title)); link.href = obj.url; let date_trailer = document.createElement('span'); el.appendChild(date_trailer); //date_trailer.appendChild(document.createTextNode(' ('+year+'-'+month+')')); date_trailer.appendChild(document.createTextNode(' ('+MONTHS[parseInt(month, 10)]+')')); //date_trailer.style.textAlign = 'right'; //elements.push(el); list.appendChild(el); } } } }; with (scope) { eval(text); } if (cur_year == last_year) { finish(); } else { cur_year--; fetch_next_year(); } }); }); } fetch_next_year(); function finish() { for (let obj of elements) { parent.appendChild(obj); } console.log(elements); } })(); //]]> </script> <div class='clear'></div> </div> </div></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='sidebar no-items section' id='sidebar-right-2-1'></div> </td> <td class='columns-cell'> <div class='sidebar no-items section' id='sidebar-right-2-2'></div> </td> </tr> </tbody> </table> <div class='sidebar no-items section' id='sidebar-right-3'></div> </aside> </div> </div> </div> <div style='clear: both'></div> <!-- columns --> </div> <!-- main --> </div> </div> <div class='main-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> <footer> <div class='footer-outer'> <div class='footer-cap-top cap-top'> <div class='cap-left'></div> <div class='cap-right'></div> </div> <div class='fauxborder-left footer-fauxborder-left'> <div class='fauxborder-right footer-fauxborder-right'></div> <div class='region-inner footer-inner'> <div class='foot no-items section' id='footer-1'></div> <table border='0' cellpadding='0' cellspacing='0' class='section-columns columns-2'> <tbody> <tr> <td class='first columns-cell'> <div class='foot no-items section' id='footer-2-1'></div> </td> <td class='columns-cell'> <div class='foot no-items section' id='footer-2-2'></div> </td> </tr> </tbody> </table> <!-- outside of the include in order to lock Attribution widget --> <div class='foot section' id='footer-3' name='Footer'><div class='widget Attribution' data-version='1' id='Attribution1'> <div class='widget-content' style='text-align: center;'> Powered by <a href='https://www.blogger.com' target='_blank'>Blogger</a>. </div> <div class='clear'></div> </div></div> </div> </div> <div class='footer-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </footer> <!-- content --> </div> </div> <div class='content-cap-bottom cap-bottom'> <div class='cap-left'></div> <div class='cap-right'></div> </div> </div> </div> <script type='text/javascript'> window.setTimeout(function() { document.body.className = document.body.className.replace('loading', ''); }, 10); </script> <script type="text/javascript" src="https://www.blogger.com/static/v1/widgets/984859869-widgets.js"></script> <script type='text/javascript'> window['__wavt'] = 'AOuZoY7MbtELidYlTvku0pjt7YEfwHzVsA:1732544925407';_WidgetManager._Init('//www.blogger.com/rearrange?blogID\x3d4838136820032157985','//googleprojectzero.blogspot.com/2021/04/','4838136820032157985'); _WidgetManager._SetDataContext([{'name': 'blog', 'data': {'blogId': '4838136820032157985', 'title': 'Project Zero', 'url': 'https://googleprojectzero.blogspot.com/2021/04/', 'canonicalUrl': 'https://googleprojectzero.blogspot.com/2021/04/', 'homepageUrl': 'https://googleprojectzero.blogspot.com/', 'searchUrl': 'https://googleprojectzero.blogspot.com/search', 'canonicalHomepageUrl': 'https://googleprojectzero.blogspot.com/', 'blogspotFaviconUrl': 'https://googleprojectzero.blogspot.com/favicon.ico', 'bloggerUrl': 'https://www.blogger.com', 'hasCustomDomain': false, 'httpsEnabled': true, 'enabledCommentProfileImages': true, 'gPlusViewType': 'FILTERED_POSTMOD', 'adultContent': false, 'analyticsAccountNumber': 'UA-240546891-1', 'encoding': 'UTF-8', 'locale': 'en', 'localeUnderscoreDelimited': 'en', 'languageDirection': 'ltr', 'isPrivate': false, 'isMobile': false, 'isMobileRequest': false, 'mobileClass': '', 'isPrivateBlog': false, 'isDynamicViewsAvailable': true, 'feedLinks': '\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Project Zero - Atom\x22 href\x3d\x22https://googleprojectzero.blogspot.com/feeds/posts/default\x22 /\x3e\n\x3clink rel\x3d\x22alternate\x22 type\x3d\x22application/rss+xml\x22 title\x3d\x22Project Zero - RSS\x22 href\x3d\x22https://googleprojectzero.blogspot.com/feeds/posts/default?alt\x3drss\x22 /\x3e\n\x3clink rel\x3d\x22service.post\x22 type\x3d\x22application/atom+xml\x22 title\x3d\x22Project Zero - Atom\x22 href\x3d\x22https://www.blogger.com/feeds/4838136820032157985/posts/default\x22 /\x3e\n', 'meTag': '', 'adsenseHostId': 'ca-host-pub-1556223355139109', 'adsenseHasAds': false, 'adsenseAutoAds': false, 'boqCommentIframeForm': true, 'loginRedirectParam': '', 'view': '', 'dynamicViewsCommentsSrc': '//www.blogblog.com/dynamicviews/4224c15c4e7c9321/js/comments.js', 'dynamicViewsScriptSrc': '//www.blogblog.com/dynamicviews/da8f33dd880cc4f1', 'plusOneApiSrc': 'https://apis.google.com/js/platform.js', 'disableGComments': true, 'interstitialAccepted': false, 'sharing': {'platforms': [{'name': 'Get link', 'key': 'link', 'shareMessage': 'Get link', 'target': ''}, {'name': 'Facebook', 'key': 'facebook', 'shareMessage': 'Share to Facebook', 'target': 'facebook'}, {'name': 'BlogThis!', 'key': 'blogThis', 'shareMessage': 'BlogThis!', 'target': 'blog'}, {'name': 'X', 'key': 'twitter', 'shareMessage': 'Share to X', 'target': 'twitter'}, {'name': 'Pinterest', 'key': 'pinterest', 'shareMessage': 'Share to Pinterest', 'target': 'pinterest'}, {'name': 'Email', 'key': 'email', 'shareMessage': 'Email', 'target': 'email'}], 'disableGooglePlus': true, 'googlePlusShareButtonWidth': 0, 'googlePlusBootstrap': '\x3cscript type\x3d\x22text/javascript\x22\x3ewindow.___gcfg \x3d {\x27lang\x27: \x27en\x27};\x3c/script\x3e'}, 'hasCustomJumpLinkMessage': false, 'jumpLinkMessage': 'Read more', 'pageType': 'archive', 'pageName': 'April 2021', 'pageTitle': 'Project Zero: April 2021'}}, {'name': 'features', 'data': {}}, {'name': 'messages', 'data': {'edit': 'Edit', 'linkCopiedToClipboard': 'Link copied to clipboard!', 'ok': 'Ok', 'postLink': 'Post Link'}}, {'name': 'template', 'data': {'name': 'custom', 'localizedName': 'Custom', 'isResponsive': false, 'isAlternateRendering': false, 'isCustom': true}}, {'name': 'view', 'data': {'classic': {'name': 'classic', 'url': '?view\x3dclassic'}, 'flipcard': {'name': 'flipcard', 'url': '?view\x3dflipcard'}, 'magazine': {'name': 'magazine', 'url': '?view\x3dmagazine'}, 'mosaic': {'name': 'mosaic', 'url': '?view\x3dmosaic'}, 'sidebar': {'name': 'sidebar', 'url': '?view\x3dsidebar'}, 'snapshot': {'name': 'snapshot', 'url': '?view\x3dsnapshot'}, 'timeslide': {'name': 'timeslide', 'url': '?view\x3dtimeslide'}, 'isMobile': false, 'title': 'Project Zero', 'description': 'News and updates from the Project Zero team at Google', 'url': 'https://googleprojectzero.blogspot.com/2021/04/', 'type': 'feed', 'isSingleItem': false, 'isMultipleItems': true, 'isError': false, 'isPage': false, 'isPost': false, 'isHomepage': false, 'isArchive': true, 'isLabelSearch': false, 'archive': {'year': 2021, 'month': 4, 'rangeMessage': 'Showing posts from April, 2021'}}}]); _WidgetManager._RegisterWidget('_NavbarView', new _WidgetInfo('Navbar1', 'navbar', document.getElementById('Navbar1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_HeaderView', new _WidgetInfo('Header1', 'header', document.getElementById('Header1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogView', new _WidgetInfo('Blog1', 'main', document.getElementById('Blog1'), {'cmtInteractionsEnabled': false, 'lightboxEnabled': true, 'lightboxModuleUrl': 'https://www.blogger.com/static/v1/jsbin/2646514562-lbx.js', 'lightboxCssUrl': 'https://www.blogger.com/static/v1/v-css/1964470060-lightbox_bundle.css'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogSearchView', new _WidgetInfo('BlogSearch1', 'sidebar-right-1', document.getElementById('BlogSearch1'), {}, 'displayModeFull')); _WidgetManager._RegisterWidget('_PageListView', new _WidgetInfo('PageList1', 'sidebar-right-1', document.getElementById('PageList1'), {'title': 'Pages', 'links': [{'isCurrentPage': false, 'href': 'https://googleprojectzero.blogspot.com/p/about-project-zero.html', 'id': '4384467920505278144', 'title': 'About Project Zero'}, {'isCurrentPage': false, 'href': 'https://googleprojectzero.blogspot.com/p/working-at-project-zero.html', 'id': '2459334498880008057', 'title': 'Working at Project Zero'}, {'isCurrentPage': false, 'href': 'https://googleprojectzero.blogspot.com/p/0day.html', 'id': '3414239791814532209', 'title': '0day \x22In the Wild\x22'}, {'isCurrentPage': false, 'href': 'https://googleprojectzero.github.io/0days-in-the-wild/rca.html', 'title': '0day Exploit Root Cause Analyses'}, {'isCurrentPage': false, 'href': 'https://googleprojectzero.blogspot.com/p/vulnerability-disclosure-faq.html', 'id': '2935252455704572784', 'title': 'Vulnerability Disclosure FAQ'}], 'mobile': false, 'showPlaceholder': true, 'hasCurrentPage': false}, 'displayModeFull')); _WidgetManager._RegisterWidget('_BlogArchiveView', new _WidgetInfo('BlogArchive1', 'sidebar-right-1', document.getElementById('BlogArchive1'), {'languageDirection': 'ltr', 'loadingMessage': 'Loading\x26hellip;'}, 'displayModeFull')); _WidgetManager._RegisterWidget('_AttributionView', new _WidgetInfo('Attribution1', 'footer-3', document.getElementById('Attribution1'), {}, 'displayModeFull')); </script> </body> </html>

Pages: 1 2 3 4 5 6 7 8 9 10