Driving (Large) Electric

Back in 2022, I brought home a new 2023 Nissan Leaf S and I’ve had a blast driving it since. In hindsight, it was one of my best purchases in a long time– it’s super fun to drive, and other than tires/alignment it has required zero maintenance (not even refilling the wiper fluid!) in the 45 months that I’ve driven it almost 38K miles. It’s a great car.

But.

  • The Leaf’s range is not awesome. While its efficiency is high (I average 4.2 miles per KW), that’s partly achieved with a small 40KW battery pack, and the extremely limited fast-charger support (I’ve fast-charged perhaps 4 times) means that it’s completely impractical for road trips.
  • It’s small. My 13yo now rides in the front seat, and my 10yo is pretty crammed in the back.
  • It lacks features. No remote start or charge monitoring, no built-in CarPlay, small internal screen. Black cloth interior.

As early as one year in after getting my Leaf, I was already thinking about upgrading to something bigger in a year or two. I was excited that the 2026 Leaf fixes many of the problems of mine (bigger battery, nicer features, winning charger) but was disappointed to see that it’s got a backseat that seems even smaller than that of the 2023. I pondered waiting for a Tesla Model YL (the upcoming extended length version of the Y) but I’ve been souring on the Tesla because they’re everywhere nowadays and the look doesn’t appeal to me as it once did.

On June 27th, I bought an Equinox EV AWD in RipTide Blue with the cloud grey interior:

A week prior, I’d test-driven a Blazer EV and was disappointed that driving it felt … pokey. It was big and comfortable, yes, but driving it felt more like my CX-5 than my sporty Leaf, despite the 220HP electric motor. I’d initially been skeptical of going to the all wheel drive model as it cost more ($3300) and dropped estimated range (from 319 to 307), but online reviewers raved that the additional 80HP gave it the “electric car zip” that I was looking for.

So the following Saturday, as my kid warmed up at his out-of-town swim meet, I drove up from San Antonio to San Marcos (a lot further than I realized) to test drive the AWD LT2 trim. As soon as I sat down in its big comfy grey seat, I knew I wanted it. Ten-seconds off the lot in the test drive, I dropped the pedal and got that roller-coaster takeoff feel I was craving. The price was good (about $10K under sticker for the Riptide Blue one I wanted that had been used as a courtesy vehicle). Then it was just an annoying amount of paperwork before I got the keys and headed back to the meet.

I’ve only got some initial impressions, but here they are:

  • The cabin is really nice (quiet, high-riding, spacious)
  • The giant Google-powered infotainment display is really great (with a few annoyances: no CarPlay, many features locked out while driving)
  • 360 degree cameras are awesome
  • Fast-charging at up to 150KW (I consistently got 125KW at EvGo and Buc-ee’s) makes it a practical road-trip car
  • Remote start/AC is awesome, but the myChevrolet app is still annoyingly limited (e.g. cannot override charge schedule to say “Charge fully now”)
  • Having three cars is a hassle. I’d been planning for the kids to get my hand-me-downs, but it’s going to take a few years.
  • The CCS charge port is much more broadly supported than the CHAdeMO, but they really ought to throw in a NACS converter (the 2027 model is rumored to be switching to that).
  • WeatherTech floor mats are a worthwhile upgrade.
  • Selling heated seats and steering wheels in Texas (in the summer!) has to be a hard proposition. They probably should sell a “Hot Weather” config instead.

In the nine days I’ve owned the Equinox EV, I’ve driven it to and from San Antonio twice and around town a bit, but I’ve been driving my Leaf more than I expected– it’s still fun, easy to park, and 33% more energy efficient than the Equinox.

So, why I bought, in order of reasons:

  1. I need the range. I bought a house a bit further out from the city and I’ll be moving sometime in August.
  2. The Equinox offers more room for my family.
  3. I wanted it. :)

I’ll expect I’ll update this post over the next few months when I’ve got more informed things to say.

-Eric

My Car History:

  • 1990 Pontiac Grand Am (thanks, Grandma!)
  • 2003 Corolla LE 130hp (thanks, Microsoft!)
  • 2013 CX5 155hp (thanks, Telerik!)
  • 2023 Leaf S 147hp
  • 2026 Equinox EV AWD 300hp

A Quarter Century in Tech

Today marks my 25th anniversary of full-time work in tech.

June 18, 2001 – My third “New Employee Orientation” at Microsoft, starting my full-time employment after University. I worked on the Office Online PM team for three years before moving to the Internet Explorer Networking and Security teams for 8 more, eventually leading a team of PMs.

September 29, 2012 – I resigned from Microsoft to move to Austin and build Fiddler at Telerik.

January 4, 2016 – I started on the Chrome Security team at Google. Working at Google was an amazing experience and while I wasn’t supposed to be a software engineer, I managed to survive long enough to learn a ton.

June 4, 2018 – I rejoined Microsoft to work on the Edge Web Platform team. Using my newfound Chromium skills, I landed more changes into Chromium as an Edge PM at Microsoft than I had landed as a Chrome SWE at Google. lol. After four years on Edge, I moved to the Defender team, where I’ve been a PM, GPM, SWE, and Architect-in-All-But-Name.

Prior to full-time work, I spent:

  • two summers as an Electronics Test technician
  • a summer as a Delphi developer
  • a summer as an intern webdev at a Federal contractor
  • a spring as a webdev intern at The Motley Fool
  • two summers interning at Microsoft on the product that would become SharePoint
  • two semesters as a Student Consultant for Microsoft at the University of Maryland

I don’t have anything newly profound to share today, but much of what I’ve learned over this quarter-century is summarized in some of the many posts on Career I’ve posted over the last thirteen years. Back in 2015, I gave a talk about what I’d learned in my first fifteen years: you can find the recording and deck of Lucking In on GitHub.

Tempus fugit!

Participatory Extensible Security

In the past, I’ve explained how security products combine sensors and throttles with threat intelligence to protect users and devices from attack. I’ve also outlined how the evolution of software, including increased complexity and a focus on privacy, have made it harder than ever for sensors and throttles to function effectively, leading to security and reliability risk.

The Current Landscape

Today in the Windows ecosystem, we have a few cases of “participatory extensible security” (PES). PES is extensible on both sides:

  • An “enlightened” client can participate by asking for security help
  • Any security product can extend protection to any client

One PES example is the IOfficeAntivirus interface, which gets called on file downloads and document opens to tell installed antivirus software “I got a new file. Scan it for viruses?” (This direct call isn’t entirely redundant behavior in a world with Real-time Protection, but it’s close).

The more prominent example of PES is an API called AMSI — the Antimalware Scan Interface. I’ve blogged about AMSI before but the tl;dr is that it is an API contract where an (arbitrary) AMSI client can ask an (arbitrary) AMSI security provider “Hey, what do you think of this. Does it look malicious?

This allows the client application (a script engine, a document editor, etc) the ability to choose the best place to put a sensor/throttle pair– for instance, Word can call AMSI right after a document is decrypted and immediately before its powerful script content is about to be executed. This is great for several reasons:

  1. The client doesn’t need to know anything about the security provider.
  2. The security provider doesn’t need to try to hook the (potentially new or unknown) client.
  3. The security provider gets the content to be scanned in whatever form the client believes will best reveal signs of malice.
  4. If the content is determined to be malicious, the client can show a meaningful error message and/or offer advice or remediations.

That’s great stuff!

Unfortunately, the flexibility and simplicity of this API contract has its downsides. In particular, the API was designed in the style of most Microsoft extensibility APIs of the late 1990s: a series of registry keys point to a set of DLLs that are loaded and then executed in process of the calling app. This is theoretically good for performance because it means that an AMSI scan does not require spawning new processes or marshalling data cross-process. Unfortunately, it’s very bad for reliability. If an AMSI provider crashes or otherwise corrupts the memory of the process into which it was loaded, the AMSI client crashes. Because it’s a native code crash, there’s usually no meaningful error message, so a buggy AMSI provider can cause crashes across multiple clients without the user realizing what’s happening or that there’s a common culprit. Even if AMSI providers are rock solid in terms of reliability, implementations can silently degrade performance — most AMSI clients and providers do not show UI or any other indication that a scan is in progress or what provider is conducting it. A user could install a new product that dramatically hinders the performance of every AMSI client and suffer poor experiences for years without understanding why: “This PC is sometimes just slow, I guess.” In addition to the possibility of a single slow implementation, AMSI permits multiple providers on a single device. The performance impact of a single provider might be acceptable, but three or more? A final issue is that Windows now supports certain types of processes called Protected Processes (or Protected Process Lite) that rely on Windows Code Integrity enforcement to allow only DLLs bearing certain digital signatures to load. If an AMSI provider isn’t signed with the required signature, the LoadLibrary call will fail, that AMSI provider will be skipped, and the user’s Event Log will record a code integrity violation.

Beyond the mechanics of how AMSI providers load and run, another issue is that the API contract for AMSI is probably a bit too generic:

HRESULT AmsiScanBuffer(
[in] HAMSICONTEXT amsiContext,
[in] PVOID buffer,
[in] ULONG length,
[in] LPCWSTR contentName,
[in, optional] HAMSISESSION amsiSession,
[out] AMSI_RESULT *result );

AMSI callers calling AmsiScanBuffer in new scenarios means that AMSI providers can abruptly start getting data of sorts they’ve never seen before. For example, a few years back SharePoint started calling AMSI on inbound HTTPS request headers and bodies. In the latest Windows Insider builds, the Run dialog will call AMSI on content pasted in from the Internet to combat ClickFix attacks. AMSI’s flexibility meant that existing security products didn’t need to be redeveloped with awareness of the new call sources and data, but it also introduces the risk that one of those products might misunderstand what it’s scanning and cause a false positive, performance issue, or even a crash. Even if the scan call succeeds, the value of the call depends upon the security product having meaningful threat intelligence against whatever sorts of threats might be found in the caller’s buffer. Scanning for malicious Win32 native code in a buffer containing a command line string isn’t going to be very useful, for example.

The Fix?

None of the problems here are insurmountable, we just need to invest and adjust the engineering tradeoffs to reflect more modern needs. Off the top of my head, I’m hoping we’ll see:

  1. Telemetry for the AMSI providers to understand their real-world performance impact
  2. UX for the user to understand how their security software impacts performance and reliability
  3. An API contract that does not result in loading foreign code into every AMSI caller
  4. A richer API contract that allows for more context on what’s being scanned
  5. A richer API contract that allows for more result codes

I’m hopeful that one day we’ll be able to fold the legacy AMSI features into the upcoming Windows Endpoint Security Platform that is being built as a part of the Windows Resiliency Initiative.

Spring 10Ks

After two solid half-marathons early this year, I was excited for the start of the 10K season to see whether I could keep improving my times. I had mixed results.

Cap10K

On Sunday, April 12th, I awoke at 5:20 before my alarm, had a cup of coffee and a banana. I left the house at 6:40, but the entrance ramp to MoPac was closed so I had to take a slower detour. I got to my usual parking lot at 7:10 and there were plenty of spaces. Considering the drizzle, I put on a poncho and headed to the PortaPotty for a (alarmingly productive) pre-race bathroom break. I managed to get into the back of Corral B before it closed. While waiting for the race to start, I had a pack of Jelly Belly Energy beans and an Apple Cinnamon Gu packet– the latter a mistake, as it felt like it was going to come up later in the race. This was my second bad experience with pre-race apple cinnamon snacks.

Every mediocre race can yield a list of excuses about why it didn’t go well, and this was no exception.

  • It was drizzling and somewhat muggy throughout. I’d failed to prepare all of my gear the day before, and couldn’t find either of my usual tank tops to run in.
  • The runners in Corral B were slow (with a non-trivial number of people already walking in the first half mile) and it was very crowded, so my start was slow. Still, I managed a respectable first 5K at 28:17, but would need a negative split if I wanted to achieve my goal of PR (<52:25). Alas, my second half fell apart.
  • My MP3 player was in a state where it wasn’t allowing me to choose one artist to play, so I switched over to play music from my COROS Pace 3 watch, but even at maximum volume, it was too quiet to hear. So most of my run was just the sound of runners’ feet and the occasional band. :'(

The “King of the Hill” hill wasn’t nearly as steep or long as I remembered, and I managed to run it and the following long slope without stopping. My favorite sign was one around mile 4 that had a drawing of Rocky from Project Hail Mary with the words “AMAZE AMAZE AMAZE” on it.

Alas, I ended up well behind my goal and even my backup goal (under an hour), but it wasn’t a bad time (1:01:36), just somewhat disappointing.

More photos / Timecard

Chart from my Coros Pace3 running watch:

Austin Sunshine Run 10K

I first started running the Sunshine Run after a disappointing showing in the 2024 Cap10K but it hadn’t proven to be a good consolation race, with slow times in both 2024 and 2025. Still, I had high hopes for this year, because I felt like most of the blame for my slow Cap10K belonged on the weather.

The morning of the race, I was well behind schedule because I needed to drop my son at a swim meet, so I didn’t get to the parking lot until 7:32, not long before the 8am start. I managed a worryingly-productive visit to a PortaPotty and got into the race corral a hundred feet behind the time-targeted groups. As a much smaller race (~3K participants), I successfully managed to weave through the slow starters and managed a 7:43 mile. I was feeling good. The weather was absolutely perfect, sunny, with temps in the high 50s and a light wind. My new MP3 player worked well enough with my JLab headphones.

The “big hill” I was dreading in this race was again not nearly as intimidating as expected (this is a recurring pattern), and I ran the whole thing. I didn’t take a break until mile 4, and even then it was a very brief break. Around mile 5, I dropped to a walk but after about 15 seconds a group of high-energy college kids (who’d paused for a dance break in front of the last band) started cheering me on as they came by and I got back into a run for the remainder of the race.

Frustratingly, I had no idea how close I was to getting my 10K PR or I probably could’ve snagged it without too much effort. Still, at 53:12, I crushed my goal (sub-1:00) and beat last year’s time by 10:21.

https://results.laurelt.com/asr/results?pk=8807833

Last year, I’d won a prize in the raffle and spent a ton buying a signed football for the fundraiser; this year, I again won a prize from St. Elmo Brewing in the raffle.

I really enjoyed this race and was smiling for the next few days.

-Eric

Cybersecurity Metaphors

Uneven Protection

Attacks flow like water: if you have a hole in your defenses, attacks will flow through that hole. Unless they’re trying to win a prize or show off, attackers do not bother attacking where your security posture is strongest.

Making your tallest wall taller usually isn’t useful.

Encryption

Security folks love encryption, for good reason. Proper encryption provides confidentiality (your secrets are secret) and integrity (no one can modify your encrypted data). The problem is that encryption is based on a secret key, and if you don’t protect that key, you likely haven’t done much of consequence. Effectively protecting the key is very difficult.

Enclaves

Enclaves provide a secure location to operate on secrets. Unfortunately, many implementations of secure enclaves are naive and provide no meaningful protection. One common problem is that the enclave acts as a confused deputy, fully willing to satisfy the requests of any attacker.

Spontaneously-Combusting Fire Extinguishers

The whole point of security software is to try to achieve the impossible: “prevent bad things from happening.” Unfortunately, the means of providing this protection often involves poking into the most sensitive areas of a system to attempt to detect malicious activity. This is a high-risk endeavor, and any error can end up causing the exact sort of IT disaster you were hoping to prevent.

It is crucial that security software not be a “cure that’s worse than the disease” or, as I prefer to describe it, “a fire extinguisher that intermittently spontaneously combusts and burns down the building.”