Security risks associated with expansion cards

I agree with Korvin that this can be an additional issue to be aware of if you have a reason to be worried about hardware security.

I also agree that it won’t make any difference for the typical user because they are already at risk. This includes any of the following:

  • You have ports on the back side of your laptop and you don’t check them every time before you unlock it (assuming that a modern OS won’t accept USB devices while the machine is locked).
  • You leave it unattended for long enough to open+modify+close, i.e. a few minutes.
  • You don’t block almost all USB devices by default. If you have whitelisted even one USB keyboard and the attacker might know which one, they can prepare a rubber ducky with the right VID:PID and plug it in while you are using the laptop. I would consider this a less targeted attack than making a special Framework module.
  • You might be tricked into entering you password on a similar-looking machine (see remarks about stickers earlier in this thread).

Nonetheless, there are a few situations when a Framework laptop may be more at risk. These are the ones to be aware of.

Enter: The paranoid user. They use Qubes to lock any external communication in a VM (USB, network, etc). USB input device will not be able to control the system unless the user allows this (there will be a security prompt). They won’t leave the machine unattended and they will notice additional devices that are plugged while they are distracted.

So, the important question is whether we can distract them and swap an extension module for a malicious one with them being none the wiser. Pickpockets can bump into you, pick your wallet, take the money while you are distracted and put the wallet back in its place. So I think it is possible.

How can we exploit this?

Not with a simple BadUSB device because that would still be blocked. We can make an expansion card that is a passive USB snoop that forwards USB data via Bluetooth. Then, the paranoid user goes home, they plug in their corded USB keyboard and think they may safely enter the important passwords that they would never use outside the safety of their home. They will get the security prompt about the USB device, of course, but they will accept it because they know that their keyboard hasn’t been tampered with.

Is it possible to build such a malicious expansion card?

Buy an original USB-C expansion (to have no difference in the exterior) and swap the PCB. Take any of the ESP32 variants that have USB OTG. It will need some modification in software or hardware so it won’t reply to USB messages. This will only speak USB 1.1 so the user might notice the difference if their device usually speaks USB 2.0. Cost would be 10€ for the expansion card plus 5€ for an ESP32 breakout board. One could use a small FPGA (e.g. ICE40) with an USB ULPI PHY to avoid this. I think this would still fit into the expansion card. With two PHYs, one could even make this a MITM style attack and inject malicious key press events. This will increase the cost to 25-50€ (assuming you pay normal prices, not what we currently have).

Why is this different for Framework than for another laptop?

  • You cannot install anything inside a laptop while merely distracting the user.
  • Device plugged into normal laptop ports are easy to be noticed. A paranoid user won’t miss this.
  • Expansion cards may be perceived as part of the laptop but they are more like peripherals security-wise.
  • A small device might go unnoticed (like Logitec receiver or Tomu) but it won’t be able to intercept USB signals.

What can we do about this as users of Framework?

  • First and foremost, be aware of it.
  • If you don’t plan to swap them, glue them down with epoxy. This may be a good option for the really paranoid users but it would be a pity to disable this feature of Framework.
  • Glue them down with stickers or tape so they cannot be swapped without tearing off or ripping through the tape. They cannot be easily hot-swapped anymore but you can later undo it.
  • Glue down some ports, treat the others as untrusted.
  • Mark the cards with stickers and scratches and check them each time you need to trust them (as suggested by others in this thread). I would add that you might want to put stickers on the seams or fill the cards with epoxy. Otherwise, they might be stolen, modified and put back.

Could Framework be modified to improve on this situation?

Korvin already suggested a button for the eject switch. It probably won’t be as easy or cheap as we might hope. It has to be reliable, i.e. the mechanical design that actuates the button has to work well for thousands of devices. This can be a challenge to get right. I would very much welcome such a button but I’m not sure if the cost and development effort is a good investment because only few users will care.

Most users will swap cards at will so the button shouldn’t do anything harmful by default, e.g. certainly don’t lock the system. I suggest that EC keep a counter of swap events. This won’t have any effect by default. Users who are interested in this feature have to write some scripts that query the counter and show a notification whenever it increases. The BIOS could append the counter to a TPM register, which users may decide to tie into secure boot - but I guess this is too extensive even for paranoid users. The EC might be active and able to detect eject events while the system is turned off. If it is not, users must be aware that events will be missed in this case.

If there is enough space, we might be able to add the button ourselves. I don’t think we can tie it into the EC but there should be enough space for an ESP32 somewhere. I don’t see how we would talk to the ESP32 without blocking one of the USB ports for this so maybe we should put it into one of the expansion spaces, as has been suggested elsewhere. We have EC source code. Sweet. I had underestimated the awesomeness of Framework :slight_smile:

In addition, I would really love to have some pins for low-speed out-of-band signaling in addition to the USB-C port:

  • This could be I2C like the expansion ports of PinePhone and Jolla. Power supply might be shared with VBUS of the USB-C connector, I think (but this needs careful consideration to not violate any USB specs).
    • By default, this might connect to a EEPROM that says which kind of module is connected.
    • It will allow for all kinds of low-speed modules (see PinePhone back covers, LoRa, LED, NFC, …) and the USB-C port can be passed through without any loss of function.
  • SPI could be for security modules. That way, the expansion card can authenticate to the laptop in a way that cannot be faked/copied.
    • This could be a full TPM but something cheaper like ATECC608A should work as well. Any MCU with trusted boot would work as well (e.g. ESP32, many ARM and RISC-V) albeit with maybe a slightly lower level of security.
    • PinePhone uses an I2C-to-SPI chip for one of the back covers and there may be security chips with an I2C interface so not having SPI is not a show-stopper (if we did have I2C, that is).
    • Modules would be inspected by users and then sealed with epoxy so steal+modify isn’t possible.
    • It is up to the user to initialise the security chip and do something useful if auth fails at a later point, e.g. block that USB port in the kernel.
  • While we are at it, add a voltage input so alternative charging ports can be implemented without blocking the USB-C port, e.g. like the dual USB-C card that has been suggest in another thread.
3 Likes

Some information on the EC from this datasheet and the EmbeddedController repo:

  • The EC debug header has all four JTAG signals but the EC is configured for SWD. This means that TDI and TDO are unused. An alternate function of these pins is I2C09 or UART02 so there is a good chance that we can use these for some other purpose.
  • The pinout header lists four I2C interfaces. If we can access the pins without too many problems, this would be another way to talk to hardware that we add: Battery charger, power delivery, touchpad, and thermal. A 5th I2C is “Reserved for HID” but I don’t know whether we will be able to access these signals.
    • We have to make sure that any added hardware uses I2C addresses that don’t conflict with devices that are already present on the bus.
    • The EC has 5+3 I2C interfaces that can be muxed to 16 pinouts so a dedicated I2C interface for each expansion port might be possible for future versions of the mainboard.
    • I wouldn’t want to expose the touchpad to passive snooping by an expansion card but the thermal I2C might be ok for this. The CPU should protect itself on overtemperature anyway and there is also a PECI interface for getting temperatures from the CPU. A malicious expansion card could already be a USBKiller (albeit with rather small capacitors) so I don’t think that we have to worry too much about “vandalism”.
    • If we only have one I2C interface for all ports, we will need some scheme to avoid address conflicts, e.g. add two address pins and cards will need an I2C multiplexer if they use ICs that don’t support address pins.
  • The EC doesn’t have any low-power coprocessor that could monitor the eject switch. If we have a VCI_IN input available (i.e. not used but still routed to some place that we can reach with a solder iron), an eject event could wake up the EC. It will have to be long enough for the EC to start up and enable VCI_OUT. If it is too short, the VBAT logic will still latch the event (so EC will see it later) but we won’t know whether it was one event or many.
    • “CHASSIS_OPEN” is connected to pin 161, which I assume means “VCI_IN2#/GPIO161”. We could wire the eject buttons to the same input to detect them during power-off. The downside is that we cannot tell them apart from “case opened” events, which are arguably more severe.
    • VCI_IN0 and VCI_IN1 are connected to mainboard_power_button and fingerprint_power_button.
    • VCI_IN3 is not used according to the header file but this most likely means that we won’t have access to that signal.
  • We could latch eject events with some 74HCxxx logic. EC will only know whether there were some events during power-off but not how many. If we only have two GPIOs (TDI and TDO), we have to connect both switches to the same latch because we need one GPIO to read the state and another to reset the latch. Thus, reading two latches will need three GPIOs.
  • The EC can verify its firmware with a public key. If this is enabled, we won’t be able to load custom firmware. The README explains how to build the firmware and they mention a checksum that is automatically added in the build process. Therefore, I assume that custom firmware will be possible.

Wishlist:

  • Dedicated I2C for each expansion slot.
  • SPI connected to all expansion slots with dedicated chip select per slot (EC has at most one SPI to spare, unfortunately).
  • (UART might also be useful but cannot be shared and the EC doesn’t have enough of them.)
  • Some GPIOs, e.g. for interrupt, reset, JTAG_TMS (with SPI providing TCK, TDI and TDO).
  • Eject switches connected to VCI_IN3.
  • Power input pins for the expansion slots.

Realistic plan for what we can add ourselves:

  • Shared I2C for expansion slots or dedicated interfaces via an additional microcontroller.
  • Eject switches connected to VCI_IN2 or additional logic or additional microcontroller.
1 Like

Right now I have my BIOS set up to prompt for the Supervisor Password when such an event has occurred. While I have my gripes with the current implementation of that password protection (it does not seem to be required when attempting to boot from USB), I’d have no problem to be prompted for it when I change an expansion card. But then again, that would only work if the machine was powered off during the swap, so it’s not that good of a solution I guess.

Putting on my paranoid hat: If someone has opened your Framework, they won’t be stopped from booting by a supervisor password. For the trivial case, would you mind opening your Framework and disconnecting the CMOS battery for a bit? It’d be interested in what this does to your boot process, e.g. whether it forgets about the supervisor password altogether. Maybe not because UEFI might save these things on flash instead of / in addition to CMOS RAM (but maybe not to allow for the usual method of resetting it).

The important point is that you will notice the chassis open event before you enter the important passwords. A supervisor prompt will work just fine for that. I guess this means that you should attempt a normal boot (to maybe see the supervisor prompt) before booting from USB. If the supervisor password can be reset by plugging the battery, open the BIOS settings on every boot to verify that the supervisor password is still what you have set. This should be safe as long as you assume that the attacker cannot tamper with the BIOS or EC (i.e. doesn’t have basic programming skills or $20 worth of tools; oh, well… still good enough in most cases).

Ideal case, using the even more paranoid hat:

  • You have full disk encryption with anti-evil-maid protection, i.e. the bootloader / FDE password prompt will authenticate to you in some way (e.g. like the totems in Inception or remote TPM attestation to an app on your phone; “remote” can mean QR codes in this case).
    • If you haven’t, the attacker replaces the bootloader and game over.
  • The FDE prompt is encrypted and authenticated by TPM and secure boot so it cannot be modified or analysed or emulated on a different system. It appends additional data to TPM register 7 so later stages of the boot cannot pretend to be the FDE prompt (for anything related to TPM, at least).
    • If you haven’t, the attacker can add a key logger and trojan to the bootloader, e.g. there is software that will run your bootloader in a VM without knowing anything specific about your bootloader.
  • You have custom firmware for the EC with trusted boot.
    • If not, attacker replaces the EC firmware. It is trivial to make it report no chassis open event.
  • You have enrolled a trust relation between the EC and your FDE prompt.
    • If not, MITM on the eSPI communication would be possible or the EC can be replaced. That’s more involved for the attacker (most likely need soldering) so maybe out of scope. Nonetheless, there is no reason not to do this if you have custom EC firmware anyway.
  • The EC must either store events in persistent storage (system flash or its own OTP) or it must report any intermittent loss of its VBAT RAM to the bootloader. I would probably do both because it is easy compared to the other points.
  • With all of that in place, you can be certain that your FDE prompt tells the truth about whether the case has been opened or not. That is, unless there are issues in secure boot or trusted boot of the EC.
  • Bonus: Encrypt eSPI traffic for keyboard and maybe touchpad (but touchpad is still vulnerable to snooping on the I2C; keyboard also but this would need access to most of the matrix lines).
  • Bonus: Use Intel TXT in addition to secure boot. TXT has been shown to be vulnerable to SMM (system management mode) attacks on previous generations so I would only use it in addition to secure boot. TXT is only supported for the 1185G7.
  • Bonus: Most of this will be for nothing if the BIOS can be replaced. I haven’t looked into this yet but others have mentioned that coreboot wouldn’t be possible due to the CPU config. If that means that a firmware/BIOS key has been fused into the CPU, we might have some protection here. In addition, I think the EC firmware is loaded from the same flash as the BIOS so we may have some chance to detect modifications using the EC (i.e. read the BIOS parts of the flash on every start and hope that a malicious BIOS cannot fake this).

So, I think the Framework has everything that we need to make the chassis switch work even for some paranoid users. Fortunately, I don’t have any reason to be that paranoid. I hope that I will find the time to implement most of this anyway (edit: but don’t have too high hopes - that’s not near the top of my TODO list).

For whether we should conflate chassis open with the eject buttons: What would you do if your system reports an event to you, i.e. it prompts for the supervisor password? For an eject event, you would inspect the expansion cards or maybe remove them and inspect later. For a chassis open event, you would have to do a very thorough inspection of almost everything. I would argue that this is much more involved than entering the password - if you actually have any reason to worry about the safety of your devices. For most of us (including me), it really is only “because it is possible” so, yes, you are correct that we probably would just enter the password.

For myself, I think adding an MCU is most likely less work than adding the eject switches. Therefore, I would add the MCU and then we aren’t limited by the available EC pins.

1 Like

I think, this code only enables VCI_IN0 and VCI_IN1 so EC won’t wake up on chassis open (VCI_IN2). I guess this is probably a good idea in the general case because most users won’t care about the chassis switch.