Ubuntu – safely purge EFI signed kernels? (alternatively, can I get rid of unsigned kernels?)

kernelsecure-bootuefi

Can I safely un-install and purge the linux-signed* packages from my Ubuntu 16.10 (yakkety) installation?

The reason I am considering this is that my UEFI bios does not use secure boot, and my boot partition is only 200 MiB (~210 MB). I have encryption on the rest of the partitions, and I really don't want to resize them to expand the boot partition.

Unfortunately, 200 MiB is just barely too small to hold 3 kernels. The current kernels come to about 61 MiB each (that's including the abi, config, initrd, map, plus signed and unsigned kernel binaries). Adding in grub, memtest, and the partition table pushes it to about 198, which is apparently not enough free space for apt to update the kernel. I normally keep only 2 kernels (current + last), but obviously I need space for a third during the update process. If I didn't have the signed kernels (7.2 MiB each), I would be OK.

As of today, I have build versions 41, 45, and 46 of kernel 4.8.0 installed.

Will the following break my system?

apt-get purge linux-signed*
grub-mkconfig -o /boot/grub/grub.cfg

(second line added after ubfan1's comment, see below)

I believe that it should remove the following kernel packages and prevent new signed kernels from being installed:

linux-signed-generic
linux-signed-image-4.8.0-41-generic
linux-signed-image-4.8.0-45-generic
linux-signed-image-4.8.0-46-generic
linux-signed-image-generic

I have all of the regular (unsigned) versions of these packages installed.

As a side question, does anyone know why the unicode.pf2 file (2.3 MiB) appears in both /boot/grub and /boot/grub/fonts? I diffed the files and they are exactly the same. I assume this is the font used on the grub menu, but why does it appear twice on the same partition? I feel silly wrangling about 2.3 MiB, but that could also make a huge difference in my particular case.

Thanks!

added info for ubfan1's comment

The .efi.signed kernels appear in every menu entry in /boot/grub/grub.cfg. I know that my uefi firmware (I guess bios isn't the right term anymore) does not use secure boot, but the grub config files seem to think that it does. Obviously my system boots the signed kernels just fine, so maybe I can purge the unsigned kernels instead?

I dug into /etc/grub.d/10_linux to find where these lines come from, and found the following code:

if test -d /sys/firmware/efi && test -e "${linux}.efi.signed"; then
    sed "s/^/$submenu_indentation/" << EOF
    linux   ${rel_dirname}/${basename}.efi.signed
      root=${linux_root_device_thisversion} ro ${args}
EOF
  else
    sed "s/^/$submenu_indentation/" << EOF
    linux   ${rel_dirname}/${basename}
      root=${linux_root_device_thisversion} ro ${args}
EOF
  fi

I'm no bash expert, but I think I follow this in pseudo code

if /sys/firmware/efi AND /boot/vmlinuz-x.x.x-xx.efi.signed exist
  echo linux vmlinuz-x.x-xx-generic.efi.signed to /boot/grub/grub.cfg
else
  echo linux vmlinuz-x.x.x-xx-generic to /boot/grub/grub.cfg

so, if I purge the signed kernel packages, then re-run grub-mkconfig, it should put the regular unsigned kernels into grub.cfg, right?

Best Answer

Thanks for all the help and links. I spent a few hours this weekend and verified the following

Short answers

  1. Yes, you can purge all of the linux-signed* packages, but you have to install linux-generic if you want automatic kernel updates to continue functioning properly. All of the grub, kernel, and initramfs re-configuration is handled automatically. The kernel install scripts really handle everything without any issues.
    apt-get purge linux-signed* linux-generic+
  2. Yes, you can get rid of the unsigned kernels without any ill effects, but they will keep coming back after kernel updates. This cannot be solved by managing packages, but it is easy to fix with a short script.

    #!/bin/sh
    #
    # user script: 
    /etc/kernel/postinst.d/zzz-remove-unsigned-kernel
    #
    # after a new signed kernel image is installed, this script removes
    # the unsigned image
    #
    if [ -e "$2.efi.signed" ]; then
        echo "/etc/kernel/postinst.d/zzz-remove-unsigned-kernel: removing $2"
        rm "$2";
    fi
    

Longer answers

In the first case, the solution is really simple. It works pretty much as you would assume at first glance. Still I learned some helpful things about the ubuntu package structure for kernels. I wanted to be sure that I understood the side effects or consequences, but I also just like to see how things are built. Just as a side note, I use the generic kernel, but just swap generic for lowlatency or virtual if that is your thing. Also, everything here is based on 16.10 (yakkety). Here is the kernel package hierarchy: kernel package hierarchy

  • linux-signed-generic is a meta package, meaning that it doesn't include any code. It just has a list of dependencies, which always contains the complete installation of the newest kernel update. "Complete" means all of the kernel headers, the kernel image, the (detached) image signature, and extra kernel modules for just about every device that ubuntu can support.

  • linux-generic is another meta package containing all of the same real packages except for the image signature. The actual kernel image is only contained in the linux-image-x.x.x-yy package. The linux-signed-image-x.x.x-yy package just contains a detached signature, and the build script attaches this sig to /boot/vmlinuz-x.x.x.yy-generic and creates /boot/vmlinuz-x.x.x.yy-generic.efi.signed. The script does not clean up the unsigned image.

  • Kernel packages have special scripts in /etc/kernel that modify the default apt autoremove behavior. Normally, removing linux-signed-generic would flag all of the downstream packages for autoremoval, but this doesn't happen for kernel packages until there are two newer builds of the same version.

In the second case (trying to keep the signed kernel image only), there seem to be no consequences to deleting /boot/vmlinuz-x.x.x.yy-generic after the installation is complete. The two kernel images are exactly the same except for the signature, and they share all the same modules and config files. However, as soon as an updated kernel is installed, it will leave behind the unsigned image. Fortunately, there were easy hooks for running a script every time a new kernel is installed. Any scripts in /etc/kernel/postinst.d are executed by run-parts with two arguments $1 is the kernel version and $2 is the full path of the image (i.e. /boot/vmlinuz-x.x.x-yy-generic)

The only minor caveat is that removing the unsigned image has to be done after grub is finished updating grub.cfg. If /boot/vmlinuz-x.x.x-yy-generic.efi.signed exists, grub adds that image to grub.cfg and ignores the unsigned image. However, there must be somewhere in the process that still expects the unsigned image because grub fails to configure properly without it. The script that initiates grub configuration is /etc/kernel/postinst.d/zz-update-grub. I named my script zzz-remove-unsigned-kernel so that run-parts executes it after everything else is finished.

EDIT: I've used this script now with a few kernel build updates, and everything seems to work fine. I am using option 2 above (deleting unsigned kernels). I'm going to mark this as the correct answer.

Related Question