Protect GRUB2 boot loader against changes only

The version of the YaST2 Boot Loader GUI provided with OpenSUSE 13.2 failed to set the password protection for the GRUB2 boot loader. Now, after installing the newest updates it is at least possible to set a password, but the functionality is very limited - it is neither possible to choose what should be protected nor is it possible to define the user name (“root” is set as the user name by default and this is not even shown to the user, which I do not find reasonable).

Anyway, now back to my problem: I want to protect the boot loader entries against changes, but I want everybody to be able to start OpenSUSE without entering a password.

Can somebody post a description or point to a step-by-step guide suitable for OpenSUSE 13.2? Something that a mere mortal :slight_smile: can understand would be helpful, as I could not find anything appropriate on the internet.

That sounds like the default. So maybe I don’t understand the question.

The entries are defined in “/boot/grub2/grub.cfg” which is writable only by root. So the entries are protected. The default is that anyone can select which menu item to boot. If you don’t want that select option, you can set the menu timeout very short so that there is no time to select an entry.

I am referring to pressing “e” in the GRUB2 boot loader menu when booting up the system. I would also like to prevent a user from pressing “c” to enter the grub editing mode. In fact a user should only be allowed to select an existing entry in the boot loader menu - anything else should be protected by a password, thus preventing manipulation of the boot loader.

Here is the thing though if you lock it down like you want to then if there is a problem no one will be bale to fix it. Say a kernel update is broken normally going to advanced mode allows booting a previous kernel. If the Video is broken then it may be needed to boot in advanced-recovery mode. At boot it is unknown who is booting.

From what you say you want it sounds like you want to set delay to 0 or near 0. Then all will be able to boot without options. But just be warned that it may come a time that you will have to fix something and booting that way is basically broken. So be prepared to fix the system with a rescue disk and know how to chroot.

Or, instead, use the script to skip the Grub menu unless the shift key is held down. Of course, then the Users do not get a menu choice at all, just an automatic boot into the default. But, here it is again, in case it is a desired option:

Hide GRUB unless the Shift key is held down

Add the following to /etc/default/grub:

GRUB_FORCE_HIDDEN_MENU="true"

Create the following file:

/etc/grub.d/31_hold_shift

Put this in as the contents of that file:

#! /bin/sh
set -e

# grub-mkconfig helper script.
# Copyright (C) 2006,2007,2008,2009  Free Software Foundation, Inc.
#
# GRUB is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# GRUB is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with GRUB.  If not, see <http://www.gnu.org/licenses/>.

prefix="/usr"
exec_prefix="${prefix}"
datarootdir="${prefix}/share"

export TEXTDOMAIN=grub
export TEXTDOMAINDIR="${datarootdir}/locale"
source "${datarootdir}/grub2/grub-mkconfig_lib"

found_other_os=

make_timeout () {

  if  "x${GRUB_FORCE_HIDDEN_MENU}" = "xtrue" ] ; then 
    if  "x${1}" != "x" ] ; then
      if  "x${GRUB_HIDDEN_TIMEOUT_QUIET}" = "xtrue" ] ; then
    verbose=
      else
    verbose=" --verbose"
      fi

      if  "x${1}" = "x0" ] ; then
    cat <<EOF
if  "x\${timeout}" != "x-1" ]; then
  if keystatus; then
    if keystatus --shift; then
      set timeout=-1
    else
      set timeout=0
    fi
  else
    if sleep$verbose --interruptible 3 ; then
      set timeout=0
    fi
  fi
fi
EOF
      else
    cat << EOF
if  "x\${timeout}" != "x-1" ]; then
  if sleep$verbose --interruptible ${GRUB_HIDDEN_TIMEOUT} ; then
    set timeout=0
  fi
fi
EOF
      fi
    fi
  fi
}

adjust_timeout () {
  if  "x$GRUB_BUTTON_CMOS_ADDRESS" != "x" ]; then
    cat <<EOF
if cmostest $GRUB_BUTTON_CMOS_ADDRESS ; then
EOF
    make_timeout "${GRUB_HIDDEN_TIMEOUT_BUTTON}" "${GRUB_TIMEOUT_BUTTON}"
    echo else
    make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
    echo fi
  else
    make_timeout "${GRUB_HIDDEN_TIMEOUT}" "${GRUB_TIMEOUT}"
  fi
}

  adjust_timeout

    cat <<EOF
if  "x\${timeout}" != "x-1" ]; then
  if keystatus; then
    if keystatus --shift; then
      set timeout=-1
    else
      set timeout=0
    fi
  else
    if sleep$verbose --interruptible 3 ; then
      set timeout=0
    fi
  fi
fi
EOF


On 2015-04-13 00:36, gogalthorp wrote:
>
> Here is the thing though if you lock it down like you want to then if
> there is a problem no one will be bale to fix it. Say a kernel update is
> broken normally going to advanced mode allows booting a previous kernel.
> If the Video is broken then it may be needed to boot in
> advanced-recovery mode. At boot it is unknown who is booting.

Grub has had a feature to request a password for ages. I have never used
it, but it should just do what the OP is asking about.

The manual talks about it:

File: grub.info, Node: Security, Next: Images, Prev: Preset Menu,
Up: Top

9 Protecting your computer from cracking


You may be interested in how to prevent ordinary users from doing
whatever they like, if you share your computer with other people. So
this chapter describes how to improve the security of GRUB.

One thing which could be a security hole is that the user can do too
many things with GRUB, because GRUB allows one to modify its
configuration and run arbitrary commands at run-time. For example, the
user can even read /etc/passwd' in the command-line interface by the command cat’ (*note cat::). So it is necessary to disable all the
interactive operations.

Thus, GRUB provides a “password” feature, so that only administrators
can start the interactive operations (i.e. editing menu entries and
entering the command-line interface). To use this feature, you need to
run the command `password’ in your configuration file (*note
password::), like this:

password --md5 PASSWORD

If this is specified, GRUB disallows any interactive control, until
you press the key

and enter a correct password. The option --md5' tells GRUB that PASSWORD’ is in MD5 format. If it is omitted, GRUB
assumes the `PASSWORD’ is in clear text.

… (continues)

Another thing which may be dangerous is that any user can choose any
menu entry. Usually, this wouldn’t be problematic, but you might want to
permit only administrators to run some of your menu entries, such as an
entry for booting an insecure OS like DOS.

GRUB provides the command `lock’ (*note lock::). This command always
fails until you enter the valid password, so you can use it, like this:

title Boot DOS
lock
rootnoverify (hd0,1)
makeactive
chainload +1

However, the above doc is for grub 1. I do not know about grub 2, but
I’d expect similar features.


Cheers / Saludos,

Carlos E. R.

(from 13.1 x86_64 “Bottle” (Minas Tirith))

I do not have time to look into it right now, because I am tearing the head off of a friend’s Ford F150 to fix it for him and that leaves me little time for else.

However, I would expect the same as you.

As manual indicates there is no support in grub-mkconfig for now (any takers to send a patch?) You can workaround it by creating /etc/grub.d/01_auth script with content similar to

echo 'set superusers="root"'
echo 'password_pbkdf2 root grub.pbkdf2.sha512.10000.biglongstring'
echo '# HACK!'
echo 'set menuentry_id_option="--unrestricted $menuentry_id_option"'

This should come after 00_header that sets menuentry_id_option and before other scripts that actually generate menu entries. password should be generated by grub2-mkpasswd-pbkdf2 of course.

Completely untested! :slight_smile:

Your suggestion didn’t work out as expected, but you gave me the right hint. I tried the following and it works as expected (i.e. menu entries are selectable without password, but switching to the edit mode requires the password):

  1. set boot loader password using YaST2 > Bootloader GUI - this creates a new file /etc/grub.d/42_password (where one can change the default root user name or add additional users, if required)
  2. edited /etc/grub.d/00_header and added ‘set menuentry_id_option=“–unrestricted $menuentry_id_option”’ before ‘export menuentry_id_option’
  3. applied change by calling ‘sudo grub2-mkconfig -o /boot/grub2/grub.cfg’

The only problem I found so far: GRUB_DISABLE_LINUX_RECOVERY=true from /etc/default/grub seems to have no effect, as the recovery option is still available in the menu. Any idea on how to solve this?

recovery just boots without some drivers ie basic graphics etc.

Could you give some more details what did not work?

  1. edited /etc/grub.d/00_header

well, this has obvious problem on updates. For this reason I suggested to set it in separate file.

The only problem I found so far: GRUB_DISABLE_LINUX_RECOVERY=true from /etc/default/grub seems to have no effect, as the recovery option is still available in the menu. Any idea on how to solve this?

openSUSE is using heavily patched scripts so upstream documentation does not always apply. The only way to find out if this was intentional change or bug is to open bug report.

Putting the superuser and password in 01_auth_script did not enable the password protection. Steps:

  1. used grub2-mkpasswd-pbkdf2 to generate password hash and copied hash
  2. sudo joe /etc/grub.d/01_auth_script
  3. added code and inserted copied password hash:
set superusers="root"
password_pbkdf2 root grub.pbkdf2.sha512.10000.D66...
set menuentry_id_option="--unrestricted $menuentry_id_option"
  1. sudo chmod 755 /etc/grub.d/01_auth_script
  2. sudo grub2-mkconfig -o /boot/grub2/grub.cfg

Ah, well editing 00_header is then a very bad idea :shame: - the configuration should survive an update. It’s a pitty, because that had the expected effect. Any other idea on how to add the unrestricted option to every menu entry item?

Btw, using the Bootloader GUI to set the password (i.e. create the 42_password file) and then put only ‘set menuentry_id_option=“–unrestricted $menuentry_id_option”’ into 01_auth_script also does not work as expected - the unrestricted option seems not be added to the menu entries, as it asks me for the password, after I select an entry (and not only when I want to edit it).

If that is what you added verbatim it if course won’t work. Scripts in /etc/grub.d should print to standard output content of grub.cfg. Not contain content of grub.cfg. See my post, it echoes lines.

I was not aware that YaST allows you the set passwords, in this case you just need to add --unrestricted:


cat > /etc/grub.d/01_unrestricted << \EOF
#!/usr/bin/bash
echo '# HACK!'
echo 'set menuentry_id_option="--unrestricted $menuentry_id_option"'
EOF
chmod +x /etc/grub.d/01_unrestricted
grub2-mkconfig -o /boot/grub2/grub.cfg

If this does not work, please show your script from /etc/grub.d as well as generated grub.cfg.

I see. If it is done right, then it works lol!. Thanks a lot! Well, well - it has been a steep learning curve since I started trying out Linux a few days ago and I just scratched the surface :O. Hopefully it is worth the effort and I can switch from Windows to Linux for most of my tasks.