<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Eric Woo</title>
    <link>https://etw.ooo/</link>
    <description>Recent content on Eric Woo</description>
    <generator>Hugo</generator>
    <language>en-us</language>
    <lastBuildDate>Tue, 16 Jun 2026 17:00:00 -0700</lastBuildDate>
    <atom:link href="https://etw.ooo/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Pintos</title>
      <link>https://etw.ooo/posts/2026-06-16-pintos/</link>
      <pubDate>Tue, 16 Jun 2026 17:00:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2026-06-16-pintos/</guid>
      <description>&lt;h3 id=&#34;background&#34;&gt;Background&lt;/h3&gt;&#xA;&lt;p&gt;A few weeks ago, I saw &lt;a href=&#34;https://github.com/rui314&#34;&gt;Rui Ueyama&lt;/a&gt;,&#xA;author of the &lt;a href=&#34;https://github.com/rui314/mold&#34;&gt;mold&lt;/a&gt; linker,&#xA;had published a repo for a university operating systems project called&#xA;&lt;a href=&#34;https://github.com/ut-syspro-2026/pintos&#34;&gt;Pintos&lt;/a&gt;, along with a&#xA;&lt;a href=&#34;https://github.com/ut-syspro-2026/pintos-gitbook&#34;&gt;course description&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;These repos describe a project lineage through&#xA;Stanford, &lt;a href=&#34;https://github.com/jhu-cs318/pintos&#34;&gt;Johns Hopkins&lt;/a&gt;,&#xA;and other universities. Curious about this history, I looked at&#xA;&lt;a href=&#34;https://github.com/wookayin/pintos&#34;&gt;similar&lt;/a&gt;&#xA;&lt;a href=&#34;https://github.com/casys-kaist/pintos-kaist&#34;&gt;github&lt;/a&gt;&#xA;&lt;a href=&#34;https://github.com/PKU-OS/pintos&#34;&gt;repos&lt;/a&gt;&#xA;until I encountered a clone with a more detailed&#xA;&lt;a href=&#34;https://github.com/fghanei/pintos/commits&#34;&gt;commit history&lt;/a&gt;,&#xA;which included changes by the original course creator&#xA;&lt;a href=&#34;https://github.com/fghanei/pintos/commits?author=blp&#34;&gt;Ben Pfaff&lt;/a&gt;&#xA;and another well-known professor at Stanford,&#xA;&lt;a href=&#34;https://github.com/fghanei/pintos/commits?author=johnousterhout&#34;&gt;John Ousterhout&lt;/a&gt;.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Gathering Code Coverage for Sandboxed Processes</title>
      <link>https://etw.ooo/posts/2024-08-29-code-coverage-under-sandbox/</link>
      <pubDate>Thu, 29 Aug 2024 23:00:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2024-08-29-code-coverage-under-sandbox/</guid>
      <description>&lt;h3 id=&#34;motivation&#34;&gt;Motivation&lt;/h3&gt;&#xA;&lt;p&gt;While gathering code coverage for&#xA;&lt;a href=&#34;https://etw.ooo/posts/2024-06-29-youtube-unthrottle/&#34;&gt;youtube-unthrottle&lt;/a&gt;,&#xA;I encountered an interesting catch-22: tests exercising&#xA;&lt;a href=&#34;https://etw.ooo/posts/2024-07-04-porting-to-openbsd/&#34;&gt;sandboxing features&lt;/a&gt;&#xA;based on&#xA;&lt;a href=&#34;https://gitlab.com/ewoo/youtube-unthrottle/-/blob/main/src/seccomp.c&#34;&gt;seccomp-bpf&lt;/a&gt;&#xA;and&#xA;&lt;a href=&#34;https://gitlab.com/ewoo/youtube-unthrottle/-/blob/main/src/landlock.c&#34;&gt;Landlock&lt;/a&gt;&#xA;could not write coverage data to disk because of the sandbox restrictions themselves.&lt;/p&gt;&#xA;&lt;h3 id=&#34;code-coverage-approach-1-gcc&#34;&gt;Code Coverage Approach #1: gcc&lt;/h3&gt;&#xA;&lt;p&gt;The default behavior of gcc- and gcov-based code coverage is to open and&#xA;write &lt;code&gt;*.gcda&lt;/code&gt; coverage files on process exit.&lt;/p&gt;&#xA;&lt;p&gt;My first thought, upon encountering a failure to write these &lt;code&gt;*.gcda&lt;/code&gt;&#xA;files, was to investigate whether gcc supports options or APIs for&#xA;customizing this behavior: writing the coverage data elsewhere, opening&#xA;the coverage files earlier in process startup, or similar.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Sandboxing and Porting youtube-unthrottle to OpenBSD</title>
      <link>https://etw.ooo/posts/2024-07-04-porting-to-openbsd/</link>
      <pubDate>Thu, 04 Jul 2024 21:45:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2024-07-04-porting-to-openbsd/</guid>
      <description>&lt;h3 id=&#34;motivation&#34;&gt;Motivation&lt;/h3&gt;&#xA;&lt;p&gt;Given that&#xA;&lt;a href=&#34;https://etw.ooo/posts/2024-06-29-youtube-unthrottle/&#34;&gt;youtube-unthrottle&lt;/a&gt;&#xA;parses HTML and executes JavaScript fragments, it seemed appropriate to&#xA;explore sandboxing techniques that might mitigate bugs in handling&#xA;untrusted inputs.&lt;/p&gt;&#xA;&lt;p&gt;Along these lines, I&amp;rsquo;d recently been reading about OpenBSD&amp;rsquo;s&#xA;&lt;a href=&#34;https://man.openbsd.org/pledge.2&#34;&gt;pledge()&lt;/a&gt; and&#xA;&lt;a href=&#34;https://man.openbsd.org/unveil.2&#34;&gt;unveil()&lt;/a&gt; APIs on&#xA;&lt;a href=&#34;https://lwn.net/Articles/767137&#34;&gt;LWN&lt;/a&gt;.&#xA;These APIs seemed to be designed to make application-layer sandboxing&#xA;straightforward to implement, such that a program can voluntarily drop&#xA;privileges early in main() to ensure later code, even if part of an&#xA;exploit, is limited in its powers. Instead of the system administrator&#xA;configuring a sandbox around the application through blackbox-style&#xA;restrictions (like a syscall filter), the application developer makes the&#xA;sandbox &amp;ldquo;just work&amp;rdquo; out of the box.&lt;/p&gt;</description>
    </item>
    <item>
      <title>youtube-unthrottle</title>
      <link>https://etw.ooo/posts/2024-06-29-youtube-unthrottle/</link>
      <pubDate>Sat, 29 Jun 2024 01:30:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2024-06-29-youtube-unthrottle/</guid>
      <description>&lt;p&gt;A fun personal project from the past week:&#xA;&lt;a href=&#34;https://gitlab.com/ewoo/youtube-unthrottle&#34;&gt;youtube-unthrottle&lt;/a&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;usage&#34;&gt;Usage&lt;/h3&gt;&#xA;&lt;p&gt;youtube-unthrottle is essentially a tiny subset of the functionality&#xA;provided by more sophisticated tools like&#xA;&lt;a href=&#34;https://github.com/yt-dlp/yt-dlp&#34;&gt;yt-dlp&lt;/a&gt;,&#xA;&lt;a href=&#34;https://github.com/Mithronn/rusty_ytdl&#34;&gt;rusty_ytdl&lt;/a&gt;.&#xA;and the OG &lt;a href=&#34;https://github.com/ytdl-org/youtube-dl&#34;&gt;youtube-dl&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Specifically, youtube-unthrottle extracts the video and audio stream URLs&#xA;from a YouTube link passed via argv[1] and then prints the results to stdout.&#xA;This output can be combined with an external video player like mpv:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; style=&#34;color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;&#34;&gt;&lt;code class=&#34;language-sh&#34; data-lang=&#34;sh&#34;&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;uri&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;xclip -o&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;x&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;/tmp/streams.txt&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;youtube-unthrottle &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$uri&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &amp;gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$x&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;audio&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;head -1 $x&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;video&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&lt;span style=&#34;color:#66d9ef&#34;&gt;$(&lt;/span&gt;tail -1 $x&lt;span style=&#34;color:#66d9ef&#34;&gt;)&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span style=&#34;display:flex;&#34;&gt;&lt;span&gt;mpv --title&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$uri&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; --audio-file&lt;span style=&#34;color:#f92672&#34;&gt;=&lt;/span&gt;&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$audio&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt; &lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;$video&lt;span style=&#34;color:#e6db74&#34;&gt;&amp;#34;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;h3 id=&#34;motivation&#34;&gt;Motivation&lt;/h3&gt;&#xA;&lt;p&gt;The main challenge here is that YouTube stream URLs contain parameters&#xA;that must be deobfuscated using JavaScript fragments supplied elsewhere&#xA;in the YouTube payload. This is why solving this puzzle requires the use&#xA;of an embedded JavaScript engine (in this case,&#xA;&lt;a href=&#34;https://duktape.org/&#34;&gt;Duktape&lt;/a&gt;).&lt;/p&gt;</description>
    </item>
    <item>
      <title>San Francisco History: Rincon Hill and the 2nd Street Cut</title>
      <link>https://etw.ooo/posts/2024-03-30-san-francisco-2nd-st-cut/</link>
      <pubDate>Sat, 30 Mar 2024 20:00:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2024-03-30-san-francisco-2nd-st-cut/</guid>
      <description>&lt;p&gt;I recently learned that the Bay Bridge onramp at Harrison and Essex, which currently looks like:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://maps.app.goo.gl/jL52Z4x2o6jVrZ9q8&#34;&gt;&lt;img src=&#34;google_maps_harrison_at_essex.png&#34; alt=&#34;a modern-day highway entrance&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;&amp;hellip; used to look like:&lt;/p&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://opensfhistory.org/Display/wnp26.491.jpg&#34;&gt;&lt;img src=&#34;opensfhistory_wnp26.491.jpg&#34; alt=&#34;a 19th century mansion&#34;&gt;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;p&gt;It turns out this part of &lt;a href=&#34;https://en.wikipedia.org/wiki/South_of_Market,_San_Francisco&#34;&gt;SoMa&lt;/a&gt; was originally a well-to-do residential area, until Rincon Hill was demolished in order to make 2nd Street less steep. The upper right-hand corner of this photograph shows 2nd Street passing over Rincon Hill, before the so-called 2nd Street Cut:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Guiding the OOM Killer toward Firefox subprocesses</title>
      <link>https://etw.ooo/posts/2022-05-18-firefox-oom-killer/</link>
      <pubDate>Wed, 18 May 2022 06:15:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2022-05-18-firefox-oom-killer/</guid>
      <description>&lt;p&gt;I recently figured out a combination of cgroups usage and scripting that&#xA;improves how my desktop behaves under web-related memory pressure.&lt;/p&gt;&#xA;&lt;h3 id=&#34;systemd-units&#34;&gt;Systemd Units&lt;/h3&gt;&#xA;&lt;p&gt;Use &lt;code&gt;memcg&lt;/code&gt; to restrict &lt;code&gt;firefox&lt;/code&gt; processes in aggregate to N% of system RAM:&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ cat /usr/lib/systemd/system/firefox.slice&#xA;[Unit]&#xA;Description=Firefox&#xA;Before=slices.target&#xA;&#xA;[Slice]&#xA;MemoryAccounting=true&#xA;MemoryMax=75%&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Customize &lt;code&gt;OOMPolicy&lt;/code&gt; such that &lt;code&gt;systemd&lt;/code&gt; allows parent &lt;code&gt;firefox&lt;/code&gt; processes to&#xA;continue living, even if their children are OOM-killed.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code&gt;$ cat /usr/lib/systemd/system/firefox.service&#xA;[Unit]&#xA;Description=Firefox&#xA;After=network.target&#xA;&#xA;[Service]&#xA;Environment=DISPLAY=:0&#xA;ExecStart=/usr/bin/firefox-nightly&#xA;OOMPolicy=continue&#xA;Slice=firefox.slice&#xA;User=my-username&#xA;&#xA;[Install]&#xA;WantedBy=graphical.target&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;Run &lt;code&gt;firefox&lt;/code&gt; under this &lt;code&gt;memcg&lt;/code&gt; configuration:&lt;/p&gt;</description>
    </item>
    <item>
      <title>Choosing Hugo and GitLab Pages</title>
      <link>https://etw.ooo/posts/2021-08-02-choosing-hugo-and-gitlab-pages/</link>
      <pubDate>Mon, 02 Aug 2021 11:30:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2021-08-02-choosing-hugo-and-gitlab-pages/</guid>
      <description>&lt;p&gt;It seems reasonable, in the spirit of self-documentation, for the first&#xA;real post to this site to describe the creation of the site itself.&lt;/p&gt;&#xA;&lt;h3 id=&#34;hosting&#34;&gt;Hosting&lt;/h3&gt;&#xA;&lt;p&gt;The precipitating event for creating this site was my finding out about&#xA;the &lt;a href=&#34;https://icannwiki.org/.ooo&#34;&gt;.ooo TLD&lt;/a&gt;, which formed a clear &lt;a href=&#34;https://en.wikipedia.org/wiki/Domain_hack&#34;&gt;domain&#xA;hack&lt;/a&gt; with my family name.&lt;/p&gt;&#xA;&lt;p&gt;I used &lt;a href=&#34;https://domains.google&#34;&gt;Google Domains&lt;/a&gt; to test URLs for&#xA;availability and eventually settled on &lt;a href=&#34;https://etw.ooo&#34;&gt;this one&lt;/a&gt;,&#xA;then completed the purchase through Google Domains.&lt;/p&gt;&#xA;&lt;p&gt;I chose &lt;a href=&#34;https://docs.gitlab.com/ee/user/project/pages&#34;&gt;GitLab Pages&lt;/a&gt;&#xA;for hosting. I considered &lt;a href=&#34;https://pages.github.com&#34;&gt;GitHub Pages&lt;/a&gt;&#xA;initially, but when I could neither access my GitHub account (second&#xA;factor and recovery codes all failed) nor recover it (still waiting on&#xA;response from GitHub support), I went with a different option.&lt;/p&gt;</description>
    </item>
    <item>
      <title>Hello, World!</title>
      <link>https://etw.ooo/posts/2021-07-28-first-post/</link>
      <pubDate>Wed, 28 Jul 2021 23:45:00 -0700</pubDate>
      <guid>https://etw.ooo/posts/2021-07-28-first-post/</guid>
      <description>&lt;p&gt;I will add some simple content in subsequent posts. For now, I am starting with&#xA;the most basic content possible.&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
