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 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.