Making GRUB quiet

While traveling, I have been asked a few times by security agents at airports to turn on my laptop, and well, show them it did work, and looked like a real computer.

Although they never searched the content and nothing bad ever happend, every time I cross the border or go through security I am worried about what might happen, especially given recent stories of people being searched and their laptops taken away for further inspection.

The fact I use full disk encryption does not help: if I was asked to boot, my choice would be to either enter the password and login, thus disclosing most of the content of the disk, or refuse and probably have my laptop taken away for further inspection.

So.. for the first time in 10 years, I decided to keep Windows on my personal laptop. Even more, leave it as the default operating system in GRUB, and well, not show up GRUB at all during boot.

Not because I think it is safer this way, but just to create as little pretexts or excuses for anyone to further poke at my laptop, in case I need to show it or they need to inspect it.

Getting grub out of the way was not as easy as it should have been, so this post is to document what I did.

Problems

First of all, here are the problems:

  • The Debian GRUB setup scripts create a menu entry in GRUB for each kernel you have installed, followed by other detected Operating Systems. This means that every time you install a new kernel, the entry number of other Operating Systems change (eg, Windows becomes the 3rd entry, or 4th entry, ...). Given that the default Operating System is specified by entry number, if you want to default to windows, well, it doesn't play out well.

  • By default, GRUB will show a menu. If you disable that menu (relatively easy), it will still show a "Loading GRUB." message followed by "Welcome to GRUB!", something like:

     Loading GRUB. 
     Welcome to GRUB!
    

    Turns out that those messages are not configurable, as they are printed before any config file can be read by GRUB. Ubuntu and a few other vendors have provided a patched version of GRUB, but I really don't want to go down that path: don't want to keep installing my own version of GRUB or patch and recompile for each new release.

So, here's what I did...

Fixing the order of the entries

There might be better ways to provide a default that is not an integer, the name of an entry, for example. However, I really wanted windows to show up first in GRUB.

To fix the order of the menu entries, I:

  1. Opened /boot/grub/grub.cfg, and manually copied the entry for Windows I wanted to keep. In my case, the entry was:

     menuentry "Windows 7 (loader) (on /dev/sda2)" --class windows --class os {
             insmod part_msdos
             insmod ntfs
             set root='(hd0,msdos2)'
             search --no-floppy --fs-uuid --set=root F646B41846B3D817
             chainloader +1
     }
    
  2. Disabled automated discovery of operating systems. I don't care, I don't install new systems that often, and when I do, I'm well aware I have to update grub config. To do so, you need to:

     $ sudo -s
     # vim /etc/default/grub
     ...
     GRUB_DISABLE_OS_PROBER=true
    

    eg, add GRUB_DISABLE_OS_PROBER=true to /etc/default/grub.

  3. In /etc/grub.d, added a script 06_windows like this:

     $ sudo -s
     # cd /etc/grub.d
     # cat > 06_windows <<EOF
     #!/bin/sh
     exec tail -n +3 $0
    
     menuentry "Windows 7 (loader) (on /dev/sda2)" --class windows --class os {
             insmod part_msdos
             insmod ntfs
             set root='(hd0,msdos2)'
             search --no-floppy --fs-uuid --set=root F646B41846B3D817
             chainloader +1
     }
     EOF
     # chmod 0755 ./06_windows
    
  4. Run update-grub to get the grub configuration updated for real.

  5. Checked the content of /boot/grub/grub.cfg manually, and reboot to verify. Windows should be the first entry now.

Disabling the boot menu

This was relatvely easy to do, just edit /etc/default/grub, make sure you have the following lines:

GRUB_DEFAULT=0
GRUB_TIMEOUT=0
GRUB_HIDDEN_TIMEOUT=5
GRUB_HIDDEN_TIMEOUT_QUIET=true

The first line will tell grub to start Windows by default (the first boot entry), the second one tells grub to show the menu for 0 seconds by default, thus not showing it, the 3rd one will wait for 5 seconds for you to press a key before the menu, the last one will not show the counter going from 5 to 0 before showing the menu.

The only hiccup I had here was that most of the documents say you have to hold shift to get into the menu, but no, for me I had to press ESC, or any other key? I still need to try :).

Don't forget to run update-grub and reboot to test this out. You should see that despite the changes, you will still have a Loading GRUB. message, and a Welcome to GRUB!, although nothing else will show up before booting Windows.

Disabling the boot messages

So, how do you get rid of the annoying:

Loading GRUB.
Welcome to GRUB!

? Most forums and online discussions will tell you to patch the GRUB source code and recompile. Those messages are printed out well before any config file can be loaded, and there are really not that many alternatives.

I really didn't want to patch, as I did not want to maintain a set of patched binaries for my own use on my own system (yes, I love keeping the system up to date! And I love playing with testing/unstable, which means frequent updates).

The idea was simple: if the messages are displayed, they must be stored somewhere. And if any equivalent of printf is used, I can replace the first character of each of those strings with a \0 to prevent them from showing up.

This is terribly terribly hacky. But 2 hours of work to find the right files and the right process gave me exactly what I wanted: a tool that modifies a few of the grub files to remove the messages, which works like a charm.

By adding a hook in /etc/initramfs-tools or /etc/grub.d, I can just run the tool every time grub configs are changed, without having to recompile and patch the source.

I've just uploaded some code to github if you want to try it. Read the README, but it should be really straightforward to get it rolling.

Again, don't expect too much, it's not clean and beautiful, it only works.

What next?

Most distributions used an entirely different path: patching GRUB to unconditionally disable those messages. As a user, I'd rather prefer to have the choice to disable those messages or not, especially given the fact that those messages can be useful for debugging.

Unsurprisingly, the GRUB maintainers refused those patches, which are now maintained separately by each distro that includes them.

Related to grub-shusher, I will need to update it every time bootstrap.S and a few other .S files change in GRUB. This doesn't happen often, but I am sure I will eventually grow tired of maintaining it.

It would still be great to have a real, supported, solution for configuration parameters that are needed before, well, a configuration file can be read and loaded.

Here are some proposals:

  • It would not be hard to add some sort of watermark before each configuration variable in the .S file, and binary blobs? Then we could have a tool like grub-shusher that reliably can find those watermarks, the corresponding variables, and change them directly into the binary? For example, in bootstrap.S we could have a bool to determine if messages have to displayed or not, code would check that bool value before displaying the messages. Before that bool definition, we can add a watermark like 0xabcd (any value that is not used throughout the binary, really) to indicate that the following bytes are a configurable bool? Have something like grub-shusher find those watermarks, and allow to change them. This is probably worth doing if there are more variables than well, just one.

  • Ship GRUB with variances of kernel.img, with different parameters compiled in, and let grub-install figure out which variances to install on the MBR based on user configs or command line flags. This would work only if there are a handful of variables, as the number of combinations would explode exponentially. It seems brittle, but would work.


Other posts

Technology/Perl