70 stories
·
4 followers

Kees Cook: UEFI booting and RAID1

2 Comments

I spent some time yesterday building out a UEFI server that didn’t have on-board hardware RAID for its system drives. In these situations, I always use Linux’s md RAID1 for the root filesystem (and/or /boot). This worked well for BIOS booting since BIOS just transfers control blindly to the MBR of whatever disk it sees (modulo finding a “bootable partition” flag, etc, etc). This means that BIOS doesn’t really care what’s on the drive, it’ll hand over control to the GRUB code in the MBR.

With UEFI, the boot firmware is actually examining the GPT partition table, looking for the partition marked with the “EFI System Partition” (ESP) UUID. Then it looks for a FAT32 filesystem there, and does more things like looking at NVRAM boot entries, or just running BOOT/EFI/BOOTX64.EFI from the FAT32. Under Linux, this .EFI code is either GRUB itself, or Shim which loads GRUB.

So, if I want RAID1 for my root filesystem, that’s fine (GRUB will read md, LVM, etc), but how do I handle /boot/efi (the UEFI ESP)? In everything I found answering this question, the answer was “oh, just manually make an ESP on each drive in your RAID and copy the files around, add a separate NVRAM entry (with efibootmgr) for each drive, and you’re fine!” I did not like this one bit since it meant things could get out of sync between the copies, etc.

The current implementation of Linux’s md RAID puts metadata at the front of a partition. This solves more problems than it creates, but it means the RAID isn’t “invisible” to something that doesn’t know about the metadata. In fact, mdadm warns about this pretty loudly:

# mdadm --create /dev/md0 --level 1 --raid-disks 2 /dev/sda1 /dev/sdb1 mdadm: Note: this array has metadata at the start and may not be suitable as a boot device. If you plan to store '/boot' on this device please ensure that your boot-loader understands md/v1.x metadata, or use --metadata=0.90

Reading from the mdadm man page:

-e, --metadata= ... 1, 1.0, 1.1, 1.2 default Use the new version-1 format superblock. This has fewer restrictions. It can easily be moved between hosts with different endian-ness, and a recovery operation can be checkpointed and restarted. The different sub-versions store the superblock at different locations on the device, either at the end (for 1.0), at the start (for 1.1) or 4K from the start (for 1.2). "1" is equivalent to "1.2" (the commonly preferred 1.x format). "default" is equivalent to "1.2".

First we toss a FAT32 on the RAID (mkfs.fat -F32 /dev/md0), and looking at the results, the first 4K is entirely zeros, and file doesn’t see a filesystem:

# dd if=/dev/sda1 bs=1K count=5 status=none | hexdump -C 00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................| * 00001000 fc 4e 2b a9 01 00 00 00 00 00 00 00 00 00 00 00 |.N+.............| ... # file -s /dev/sda1 /dev/sda1: Linux Software RAID version 1.2 ...

So, instead, we’ll use --metadata 1.0 to put the RAID metadata at the end:

# mdadm --create /dev/md0 --level 1 --raid-disks 2 --metadata 1.0 /dev/sda1 /dev/sdb1 ... # mkfs.fat -F32 /dev/md0 # dd if=/dev/sda1 bs=1 skip=80 count=16 status=none | xxd 00000000: 2020 4641 5433 3220 2020 0e1f be77 7cac FAT32 ...w|. # file -s /dev/sda1 /dev/sda1: ... FAT (32 bit)

Now we have a visible FAT32 filesystem on the ESP. UEFI should be able to boot whatever disk hasn’t failed, and grub-install will write to the RAID mounted at /boot/efi.

However, we’re left with a new problem: on (at least) Debian and Ubuntu, grub-install attempts to run efibootmgr to record which disk UEFI should boot from. This fails, though, since it expects a single disk, not a RAID set. In fact, it returns nothing, and tries to run efibootmgr with an empty -d argument:

Installing for x86_64-efi platform. efibootmgr: option requires an argument -- 'd' ... grub-install: error: efibootmgr failed to register the boot entry: Operation not permitted. Failed: grub-install --target=x86_64-efi WARNING: Bootloader is not properly installed, system may not be bootable

Luckily my UEFI boots without NVRAM entries, and I can disable the NVRAM writing via the “Update NVRAM variables to automatically boot into Debian?” debconf prompt when running: dpkg-reconfigure -p low grub-efi-amd64

So, now my system will boot with both or either drive present, and updates from Linux to /boot/efi are visible on all RAID members at boot-time. HOWEVER there is one nasty risk with this setup: if UEFI writes anything to one of the drives (which this firmware did when it wrote out a “boot variable cache” file), it may lead to corrupted results once Linux mounts the RAID (since the member drives won’t have identical block-level copies of the FAT32 any more).

To deal with this “external write” situation, I see some solutions:

  • Make the partition read-only when not under Linux. (I don’t think this is a thing.)
  • Create higher-level knowledge of the root-filesystem RAID configuration is needed to keep a collection of filesystems manually synchronized instead of doing block-level RAID. (Seems like a lot of work and would need redesign of /boot/efi into something like /boot/efi/booted, /boot/efi/spare1, /boot/efi/spare2, etc)
  • Prefer one RAID member’s copy of /boot/efi and rebuild the RAID at every boot. If there were no external writes, there’s no issue. (Though what’s really the right way to pick the copy to prefer?)

Since mdadm has the “--update=resync” assembly option, I can actually do the latter option. This required updating /etc/mdadm/mdadm.conf to add <ignore> on the RAID’s ARRAY line to keep it from auto-starting:

ARRAY <ignore> metadata=1.0 UUID=123...

(Since it’s ignored, I’ve chosen /dev/md100 for the manual assembly below.) Then I added the noauto option to the /boot/efi entry in /etc/fstab:

/dev/md100 /boot/efi vfat noauto,defaults 0 0

And finally I added a systemd oneshot service that assembles the RAID with resync and mounts it:

[Unit] Description=Resync /boot/efi RAID DefaultDependencies=no After=local-fs.target [Service] Type=oneshot ExecStart=/sbin/mdadm -A /dev/md100 --uuid=123... --update=resync ExecStart=/bin/mount /boot/efi RemainAfterExit=yes [Install] WantedBy=sysinit.target

(And don’t forget to run “update-initramfs -u” so the initramfs has an updated copy of /dev/mdadm/mdadm.conf.)

If mdadm.conf supported an “update=” option for ARRAY lines, this would have been trivial. Looking at the source, though, that kind of change doesn’t look easy. I can dream!

And if I wanted to keep a “pristine” version of /boot/efi that UEFI couldn’t update I could rearrange things more dramatically to keep the primary RAID member as a loopback device on a file in the root filesystem (e.g. /boot/efi.img). This would make all external changes in the real ESPs disappear after resync. Something like:

# truncate --size 512M /boot/efi.img # losetup -f --show /boot/efi.img /dev/loop0 # mdadm --create /dev/md100 --level 1 --raid-disks 3 --metadata 1.0 /dev/loop0 /dev/sda1 /dev/sdb1

And at boot just rebuild it from /dev/loop0, though I’m not sure how to “prefer” that partition…

© 2018, Kees Cook. This work is licensed under a Creative Commons Attribution-ShareAlike 3.0 License.
Creative Commons License

Read the whole story
gcarothers
4 days ago
reply
Or why one sticks a USB UEFI boot device on to a server
Sebastopol, CA
Share this story
Delete
1 public comment
jepler
5 days ago
reply
sort of a mess, but at least it's possible. ugh.
Earth, Sol system, Western spiral arm

Apple Launching Medical Clinics for Employees

1 Comment

Christina Farr, reporting for CNBC:

Apple is launching a group of health clinics called AC Wellness for its employees and their families this spring, according to several sources familiar with the company’s plans.

The company quietly published a website, acwellness.com, with more details about its initiative and a careers page listing jobs including primary care doctor, exercise coach and care navigator, as well as a phlebotomist to administer lab tests on-site.

Seems like a great perk, but would you really want to have your primary care physician tied to your employment? What happens if you love your doctor but leave Apple?

Read the whole story
gcarothers
57 days ago
reply
The same thing that happens to everyone when they leave an employer their health insurance goes all to shit
Sebastopol, CA
Share this story
Delete

Italian Company Calls Itself ‘Steve Jobs’

1 Comment

Chaim Gartenberg, writing for The Verge:

After years of legal battles, a pair of brothers — Vincenzo and Giacomo Barbato — have successfully managed to win a legal battle against Apple, earning the right to call their company “Steve Jobs,” after Apple’s iconic founder, according to la Repubblica Napoli.

The fight began back in in 2012, when the two brothers noticed that Apple had never trademarked Jobs’ name. The pair were already in the process of starting their own clothing and accessory company, after spending years creating products for other brands, and decided that “Steve Jobs” would be the perfect name for their new brand.

I realize Gartenberg is trying to write from a neutral perspective here, but let’s face it, no one thinks they named the company “Steve Jobs” because they thought it would be a “perfect name for their new brand”. They named it “Steve Jobs” because they’re attention-seeking assholes.

Regardless what Italian trademark law says, who but an asshole would do this?

Read the whole story
gcarothers
118 days ago
reply
Maybe the same sort of asshole that names their company after an already successful record label?
Sebastopol, CA
Share this story
Delete

Face ID Can’t Approve Family Purchases

1 Comment

Samuel Axon, writing for Ars Technica:

iPhone X owners have found that Face ID isn’t available as an authentication method for the “Ask to Buy” feature, which allows parents to approve their kids’ iOS purchases and downloads. Instead, the parent (or any other “family organizer,” as Apple terms it) must enter their entire Apple account password to approve each individual purchase attempt.

Users are frustrated because equivalent functionality was available on Touch ID devices, and that functionality has been lost in the transition to the iPhone X. Face ID can be used as an authentication method for other purchases, just like Touch ID before it — but Touch ID also worked for “Ask to Buy,” and Face ID doesn’t. […]

Parents of large families with several children, each of whom might have an iOS device available to them, will find that the requests mount up quite quickly — especially right after the holidays. Kids cashing in App Store gift cards add to the requests already coming in from normal use and in-app purchases in games.

I only have one kid, but I noticed this too in the post-holiday gift card bonanza. I can’t really think of a good explanation for why Touch ID can authorize these transactions but Face ID can’t.

Read the whole story
gcarothers
119 days ago
reply
Really? "Hey Dad look at this!"
Sebastopol, CA
lukeburrage
119 days ago
Yup!
leonick
116 days ago
Which you can follow up by a bit of parenting and refunding the purchase.
Share this story
Delete

Me on React: an old dog with new tricks

2 Shares

Over the years I've been consistently uninterested in using the new slew of frameworks and libraries that have been released. By no means is this because they're bad at all, but because my particular kind of work didn't require it. However, in the last 12 months I've made significant use of React and have even released a few client projects using it. So what's changed for me? As someone who's very much "pro vanilla" and bare-metal JavaScript, why have I changed my mind so significantly?

This post really isn't for those developers out there who use tools like React daily (or Vue, Polymer, etc), but for those old dogs like me that have been resisting (for whatever reason) the new technology. Probably the old dog standardistas.

This post is written for an earlier version of me. It doesn't contain silver bullets or very much code, but hopefully it does put lay some of my previous fears to rest.

Below I've tried to outline what my original concerns were and how they've been mitigated in some way or another.

😵🔨 Overhead of tooling

This was and continues to be one of my biggest concerns when it comes to daily development. Technology is difficult enough when it moves as quickly as it does (I'm speaking in broad terms). We don't need to know everything, but it certainly helps if we're aware of everything. I remember an old project manager asking me if we should use "comet" for some software solution back around 2006 (when the concept was coined!).

So the thought of having to add some new build process to my current workflow was an initial hurdle that I really didn't want to overcome. Currently I know of grunt, gulp and webpack, but I'm 100% certain there are more tool runners and special configurations that you'll need to learn to get past the very, very first step.

Enter Create React App (henceforth known as CRA in this post). In my very first foray I tried to use CRA but got overwhelmed by the generated files, directory and config, so I aborted. Thankfully, I revisited it again a few months later, either armed with a little familiarity with React components or perhaps the config was hidden, but the big, nay huge, benefit was that the configuration is entirely hidden (though you can eject CRA and manually tune the configuration).

It meant that I could get up and running with zero configuration and I could write code and see results.

😐🖍️ A side note about styled components

As you might have guessed from my emoji title: I'm not sold. I think I understand the point of styled components, in that it will allow for the browser delivered code to include only the CSS required, but I'm still a little long in the tooth for this modern method.

In truth though, I don't know enough about the ideas behind this approach to adopt it myself. I feel (read: my gut thinks, and very little else) that styles should be kept in stylesheets and not be modified at the wim of every component that uses them. i.e. if a button style is used, it shouldn't be changed at the component level, but changed across the board of the code to consistently affect every button element. Or if it's a single "tweak" required, then it's still needed at the high level of globally accessible styles, as I've learnt over the years: it's never just once.

Bottom line though: I don't have a strong reason to use these, and I'm not entirely sure it benefits the standardista inside of me.

😭♻️ Reloading and losing state

I've posted previously about my workflow and to this day, I still use devtools for development. An important factor of using devtools is maintaining application state both for debugging but also for general development.

This means that I've interacted with my software, perhaps entered some value into a form, and when a small amount of code changes, either JavaScript or CSS or even some HTML, I do not want the state of my application to change, but only to inject and recognise the small change I've made.

The problem that I have with build tools that transpile my code to browser friendly JavaScript is that the browser quite often has to reload to recognise the newly built code. In a few examples I've tried using Angular and using System.js they both relied on a live-reload component that would reload my browser when I saved in my editor (which makes things even more confusing when the editor is devtools).

React's hot module reloading avoids this for the most part. What HMR gives me is that when a single component is changed, it is dynamically recompiled and injected into. This is an "old" (2 years) talk by Dan Abramov explaining how HMR works, in particular the core concept is explained around the 7 minute mark.

CRA has HMR turned off by default, but it doesn't require much to enable it. The index.js is changed as such:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';

const rootEl = document.getElementById('root');

ReactDOM.render(
  <App />,
  rootEl
);

if (module.hot) {
  module.hot.accept('./App', () => {
    const NextApp = require('./App').default;
    ReactDOM.render(
      <NextApp />,
      rootEl
    );
  });
}

Note the original source for this code is Chris Shepherd. I've also used this code for a few development projects and it works well.

Finally, this twitter thread also points to why HMR not turned on by default.


With HMR I'm able to maintain a large amount of application state when I'm making changes throughout my software.

For CSS, I do have the option to import CSS directly into React components (as you see above in the earlier example) but I'm not 100% sure why I would want to. I think it might be to encourage the component architecture in the CSS, or perhaps to do with code-splitting and component dependencies (but I again, I'm not entirely sure).

If I move the CSS to the public directory, now I'm able to map the directory in devtools and make direct changes inside of the elements and sources panels.

Hot module reloading retains a large amount of state, and putting CSS in to the static served directories means I can use devtools to manage styles.

😨📡 Server side support

I've spoken to a lot of individuals that I would call standardistas who have stories of projects being handed over to a React chopshop and server side support, SEO and all the rich goodness of a server delivering the content is thrown out the window.

My sense having spoken to more individuals is that server side rendering (SSR) is an extra mile that is often left off as not required or valued enough. This is my own finger-in-the-air opinion, please don't take it as gospel. Though I wonder if BigQuery could answer this question…

To me, a growing oldie on the web, even the phrase "server side render" makes no sense, since the server has to render. You can't get a client without the server (also see rants on "serverless" on twitter!). And why would a developer purposely lose the speed benefits of delivering a fully rendered tree to the client escaped me. The answer of course was: it's hard.

SSR is entirely possible with React and just requires a little diligence to get the work done. I've written about SSR before, but Jack Franklin has an excellent introduction to this and how to solve SSR with React.

More recently Next.js has come onto the scene which embraces SSR at it's core and takes the React framework to make "universal" JavaScript out of the box (universal being JS that can be run on both the server and the browser). It's a small mind shift when it comes to routing and directory structure, but it's frighteningly straightforward to follow a few of the examples from the documentation to get a SSR React application up and running.

Related: I've started a video course on Next.js that you can sign up to find out more about.

The Next.js Github repo includes a great deal of examples that cover different uses too, and in addition I completed a project for Brad Frost that uses Next.js to deliver the application earlier this year.

Below is an incredibly small demo of a web site that only prints the number of times the page has been loaded locally. It uses React and Next.js together, and importantly, to read the querystring from the initial request, Next provides a special getInitialProps method which is used to populate the component's properties.

// filename: pages/count.js
import { Component } from 'react';
import Link from 'next/link';

class Count extends Component {
  // getInitialProps allows my component to read the query string (amongst other properties)
  // this function will run for the very first time on the server when the user requests
  // this page (/count).
  static getInitialProps({ query }) {
    const { count = 0 } = query;

    // the object I return will be passed to my component as `props`, so now the props.count
    // property will be the value of the querystring.count (or zero as I am defaulting the value)
    return { count };
  }

  constructor(props) {
    super(props);

    // inside the component, I'm actually using a state value, so that it'll change every time
    // the component receives an update - but will *always* reset back to the query string
    // value set in `getInitialProps` on a full server load
    this.state = { count: parseInt(props.count || 1, 10) };
  }

  // this handler fires when the user clicks on the <Link> element that I rendered, which
  // is my chance to either read the count from props - which would have been re-loaded in
  // `getInitialProps` in a client side load, or if it's not present, we'll increment the
  // state value
  componentWillReceiveProps(nextProps) {
    this.setState({ count: parseInt(nextProps.count || this.state.count + 1, 10) })
  }

  render() {
    const { count } = this.state;

    // important to note: I am wrapping my <a> elements in a <Link> element. This will
    // "enhance" the anchor so that it can load the page locally, without the round trip
    // to the server.
    return (
      <div>
        <p>This page has been locally <Link href={`/count`}><a>loaded</a></Link> {count} {count > 1 ? 'times' : 'time'}.</p>
        <p>To manually change the number, use the query string: <Link href={`/count?count=${count + 1 }`}><a>?count={ count + 1 }</a></Link></p>
      </div>
    );
  }
}

export default Count;

Next provides a great deal of hidden magic, including JSX support without having to include the react module, but also handles the routing (based on the pages directory) and all the rendering. Here's a Glitch that you can remix and have a play around with too.

A quick proof of concept can be seen using curl and scrapping the p element (aside: scrape is a custom tool I wrote):

$ curl https://remy-next-demo.glitch.me/count\?count\=10 | scrape p --text
This page has been locally loaded 10 times.
To manually change the number, use the query string: ?count=11

This shows that the server isn't just sending an empty body tag and indeed rendering on the server fist.

Server side support does come at a price, but is not particularly harder than the client side react logic. Using Next it comes for free, but (again) at the price of a much higher abstraction.

😟 Overcoming trade-offs

There's a handful of trade-offs that I've personally noticed or I bump into regularly. The first, that will affect every author using a library or framework to some level of degree: abstraction.

Abstractions everywhere

I remember when I was starting out with jQuery (pre 1.0) and I'd often refer to the result of the foo = $('div') expression as "an array-like object". I knew that I could access foo[0] and it would give me the first element, like an array, and I could access foo.length, like an array, but it wasn't an array.

It was only until I had read through and understood a decent portion of jQuery's source code did I understand that it was borrowing the array push method to push elements into an object. Or why modifying jQuery.fn.plugin = bar would upgrade all jQuery instances.

Abstraction is everywhere, so I believe you either have to accept that you don't fully understand what's going on under the hood (this is how I feel about Next.js right now, because I've not reviewed any of the source), or you do a little research to understand how the fundamentals work.

For me, reading this post was an excellent resource. Also some reading or videos (sorry, no good links) about the Virtual DOM helps a great deal.

What stacktraces?

I've had mixed experience with stacktraces and React. In fact, the current version of CRA comes with a really good error reporting system that gives me both the source trace (which is often useless to me), but also offers a mapped trace (showing my original code), and rather magically clicking on the line will jump open to Sublime in the file and line in question. All this is overlaid in the browser window and can be dismissed if I want to ignore the error and continue with the app.

However, I've also experienced the version of reporting that's so abstracted from my code and original source that the only clues I have to the location of the error is by asking myself: what did I just change? Frustratingly Next.js (at present) suffers from this in my experience with it.

I'd also say, if I didn't have CRA to build my initial setup, I'd likely be in a mess of abstracted stacktraces.

Sadly I've had poor experience of error reporting in production. Sourcemaps seem to never really help me, and I'm left attempting to diagnose issues based on a hot mess of useless traces. I expect that this is another learning curve or tool or something that I need to discover.

All in all, it's not absolutely terrible, but for me, that's entirely down to CRA.

All the scaffolding

As a one person shop, this comes off as slightly tedious having to create a container, then a component, but I can see the benefit when sharing code with others, specifically: having a shared dialect as to how code is structured and arranged

A perceived forced structure, "finding the react way of doing things" - though I suspect all frameworks suffer from this, and there's some degree in which you can bend the rules

😍 Wins

This article has a number of frustrations that I've overcome, though it's more to reassure you, my dear reader, that the landscape really isn't as hard as I had expected.

However there's some really nice wins that come with React (and I honestly suspect this is the case with other frameworks and modern libraries available today).

I've outlined a few and included why they're important to me.

Real components

The component system that React relies on naturally puts your code into small modules designed to do a single thing. This approach has long been my aim in development, but always tricky to pull off consistently across projects.

Boilerplate aside, the most of the single files in projects I've worked on are about two scroll heights of my editor. What's important about this is that it makes debugging, testing and upgrading much easier since there's less moving parts in a single file.

Components can pull in other components and so on and the architecture organises itself in a sensible and pleasant to work with way.

Structure

Components lead nicely to structure of files. Another thing that I've personally found hard to consistently carry across different projects. Except with React. There's a number of patterns that dictate what a directory will be called (though not enforced). I recently completed a Next based project, and one of the most pleasing aspect as developer was the final directory structure.

Anything that helps me to create a consistent and replicable project structure is extremely valuable.

State machine

One of the more popular state machine libraries for React is Redux (based around Flux, though I've personally never used Flux).

I got hooked on the idea of state machines in software way back in my university days (the late 90s), then again with a talk at jQuery UK 2013 by Doug Neiner. Then after 30 minutes of watching Dan Abramov egghead (free) video tutorials on how Redux works, I was hooked 100%.

I'm a huge fan of state machines because they make developing, debugging and testing a lot simpler. This is because instead of relying on any number and combinations of user input to set my application to a specific state, I'm able to manually set the state and inject it into my system to see how it behaves (and make any necessary changes there and then).


There's a huge ecosystem around React which means there's going to be more wins to be found. One of the next items I'd like to try out Storybook which promises to let me build and design components in isolation (whereas before I was putting them individually into test pages).

Hopefully this was useful for one or two of you. Feel free to shoot me any questions you might have in the comments or as a blog post and I'll do my best to share my experience.

Originally published on Remy Sharp's b:log

Read the whole story
gcarothers
253 days ago
reply
Sebastopol, CA
Share this story
Delete

The Four Donald Trumps You Meet On Earth

2 Comments and 6 Shares

Donald Trump has said repugnant, insulting things about women—over and over and over again—for as long as he’s been in the public eye. He has called various women crazy, flat-chested, pigs. He refers to them as “pieces of ass.” He said pumping breast milk was “disgusting.”

“Women,” he told New York magazine in 1992. “You have to treat them like shit.”

Trump’s misogyny is shocking because it’s so brazen, but it’s infuriating because it’s so familiar. Chances are, if you’re a woman in 2016, you’ve heard it all before.

* * *

The first time you meet Donald Trump, he’s an older male relative who smells like cigarettes and asks when you are going to lose that weight. You’re nine years old. Your parents have to go out and buy a bottle of vodka for him before he arrives. His name is Dick. No, really, it is. At dinner one night, he explains to you that black people are dangerous. “If you turn around, they’ll put a knife in your back.” Except Bill Cosby. “He’s one of the good ones.” Turns out he’s wrong about Cosby and everything else, but the statute of limitations on Dick’s existence on Earth will run out before that information is widely available.

The next time you meet Donald Trump you’re in high school. You’re on the Academic Decathlon team because those are the kinds of extracurriculars a nerd like you gets down with. Model U.N., Thespians, Scholar Quiz, getting those good report cards with no boyfriends anywhere, girl! The teacher who’s volunteered to cover the Lit portion of the Decathlon is also the tennis coach, and he’s going over Ezra Pound’s poem, “Portrait d’une Femme,” with you and your teammates. He’s the first person who looks at you a certain way that will happen again and again for the rest of your life, as if he simultaneously can’t see you and would like to kill you. He tells you the woman in the poem is “clearly a prostitute;” which is very, very wrong.  You explain to him that this part…

Your mind and you are our Sargasso Sea,

     London has swept about you this score years

And bright ships left you this or that in fee:

     Ideas, old gossip, oddments of all things,

Strange spars of knowledge and dimmed wares of price.

…doesn’t mean that men literally pay her. Sure, she’s someone stuck in a time when she can have nothing of her own; someone who assembles her life from the odd bits she collects from others, choosing a catch-all existence over a suffocating marriage—made second-rate perhaps by her time, not by her self—but the “fee” doesn’t mean she is being paid for sex. He tells you that you just don’t get it. What he doesn’t get is that she’s a person. He is aging and bald and enjoys saying “whore” to a roomful of children. A few years later, he gets fired for having sex with a student. Him? Him. Of course him.

The next time you meet Donald Trump, he’s your boss. Well, he’s your boss’s boss. A vice president in marketing who seemingly literally cannot stop talking. He’s on his third wife, and that’ll be over in a few years. He can’t believe your mother is his age. He thinks you are friends. He asks you if you’ve changed your hair every time he sees you. Sometimes during meetings he’ll turn away and open a magazine while someone is presenting. One time he comes to a halt in the middle of his own sentence to stare at a woman’s boobs for somewhere from seven to 27 uncomfortable seconds. (It’s hard to gauge time accurately during a truly aggressive boob-stare.) When he finally gets fired years later, his HR file as fat as a pig knuckle, the rumor is he’s caught stealing his own office furniture on the weekend. They don’t even stop him. They just let him go. It’s like the building itself sighs with relief.

And then you get out of your more corporate job and become a television comedy writer on a good show, a show that keeps going. You go from staff writer to producer to co-executive producer in the space of seven years. You work with your sister, which is like a dream, and your co-workers are cool, and your boss is very, very cool. It’s almost as if the fact that you’re a woman doesn’t matter at all. At all. It’s like you finally escaped.

The Trumps are vanquished. They’re dead, or arrested, or fired, sobbing quietly into their stolen office furniture, wondering where it all went.

But then, it starts happening. The actual Trump—the real Donald Trump—starts making a bunch of noise about the birth certificate of a black man. It’s racist. It’s so racist. But it’s just background noise. Then he starts winning in the primaries. You say “no fucking way,” under your breath a lot when you read the headlines.

There he is, implying that people of color are dangerous, that women are whores, that you just don’t get it, opening a magazine while someone else is talking. There he is, all the worst people you ever had to meet, and tolerate, and fight, or at least ignore. There is the villain at the end of the horror movie rising up again with his knife and you are like: “This motherfucker again? No way, I’m tired.”

And it makes you deranged, like almost actually deranged. You engage his followers on Twitter for awhile and then decide to just tweet fart sounds at them because arguing with them is pointless. They think there is actually a discussion to be had about whether racism is okay.

You can’t believe these people and you can’t believe this guy, Donald Trump. It makes you insane to look at him, to see that look on his face that you’ve seen before when he talks about women who aren’t supermodels. When he talks about black people, or Mexicans, like he simultaneously can’t see them and wants to kill them.

And then you write a tweet about how Donald Trump is making you a loon because you’ve had to deal with him over and over again in your life, and someone from The Atlantic asks you to write a personal essay about it. You don’t write essays, you write fart jokes, but you give it a try. You write it in second person, which is a kind of writing that you are pretty sure people look down on, but screw it, you’re old now, and you’ve got money in the bank and kids and you are too tired to care what anybody thinks about your second-person narrative voice. “Who cares what readers of The Atlantic think about my second-person narrative voice,” you whisper to your cats, while secretly deeply caring.

Screw it because you aren’t that lady in that poem whom Ezra Pound can only see as a collecting bin for dribs and drabs left by men. You’ve got money and a job. You made yourself. All those other Trumps are dead, or fired, or pleaded no contest to the charge of sex with a minor, or all of the above. Because they are disasters. (Hell, even Ezra Pound wound up in an open-air cage because he was an anti-Semite and fascist sympathizer.)

Hillary’s still ahead in the polls and she looks like a comer. You bought a house in the Valley with your own dough where you found the exoskeleton of a praying mantis in the yard this morning and placed it in a Tupperware for safekeeping. An artifact, an old skin.

“There’s no one like him,” people say, “He’s unprecedented.” Maybe so, but I swear I’ve been dealing with this douchebag all my life, and let me tell you something: It doesn’t end well for him.

Because black people aren’t dangerous, and because their lives matter; because not every woman is a prostitute; and honestly because that furniture just isn’t yours, dude. The world is always watching, and you can’t get away with it forever. Go ahead and slip out of your skin into a different form. We’ll fight you again, then. Go ahead.

And by the way, Dick, if you’re reading this from Ghostville, I never lost that weight, Bill Cosby is an alleged serial rapist, and Hillary Clinton will be the next president of the United States.

Read the whole story
gcarothers
577 days ago
reply
Sebastopol, CA
Share this story
Delete
2 public comments
jhamill
573 days ago
reply
Fuck Donald Trump
California
glenn
577 days ago
reply
“There’s no one like him,” people say, “He’s unprecedented.” Maybe so, but I swear I’ve been dealing with this douchebag all my life, and let me tell you something: It doesn’t end well for him.
Waterloo, Canada
Next Page of Stories