Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

T861: op-mode: initial parts for UEFI secure boot CLI #4020

Merged
merged 4 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion debian/control
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,11 @@ Depends:
efibootmgr,
libefivar1,
dosfstools,
grub-efi-amd64-bin [amd64],
grub-efi-amd64-signed [amd64],
grub-efi-arm64-bin [arm64],
mokutil [amd64],
shim-signed [amd64],
sbsigntool [amd64],
# Image signature verification tool
minisign,
# Live filesystem tools
Expand Down
13 changes: 13 additions & 0 deletions op-mode-definitions/install-mok.xml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<interfaceDefinition>
<node name="install">
<children>
<leafNode name="mok">
<properties>
<help>Install Secure Boot MOK (Machine Owner Key)</help>
</properties>
<command>if test -f /var/lib/shim-signed/mok/MOK.der; then sudo mokutil --ignore-keyring --import /var/lib/shim-signed/mok/MOK.der; else echo "Secure Boot Machine Owner Key not found"; fi</command>
</leafNode>
</children>
</node>
</interfaceDefinition>
21 changes: 21 additions & 0 deletions op-mode-definitions/show-secure-boot.xml.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0"?>
<interfaceDefinition>
<node name="show">
<children>
<node name="secure-boot">
<properties>
<help>Show Secure Boot state</help>
</properties>
<command>${vyos_op_scripts_dir}/secure_boot.py show</command>
<children>
<leafNode name="keys">
<properties>
<help>Show enrolled certificates</help>
</properties>
<command>mokutil --list-enrolled</command>
</leafNode>
</children>
</node>
</children>
</node>
</interfaceDefinition>
2 changes: 1 addition & 1 deletion python/vyos/system/grub.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ def install(drive_path: str, boot_dir: str, efi_dir: str, id: str = 'VyOS', chro
f'{chroot_cmd} grub-install --no-floppy --recheck --target={efi_installation_arch}-efi \
--force-extra-removable --boot-directory={boot_dir} \
--efi-directory={efi_dir} --bootloader-id="{id}" \
--no-uefi-secure-boot'
--uefi-secure-boot'
)


Expand Down
6 changes: 5 additions & 1 deletion python/vyos/utils/boot.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Copyright 2023 VyOS maintainers and contributors <[email protected]>
# Copyright 2023-2024 VyOS maintainers and contributors <[email protected]>
#
# This library is free software; you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public
Expand Down Expand Up @@ -33,3 +33,7 @@ def boot_configuration_success() -> bool:
if int(res) == 0:
return True
return False

def is_uefi_system() -> bool:
efi_fw_dir = '/sys/firmware/efi'
return os.path.exists(efi_fw_dir) and os.path.isdir(efi_fw_dir)
8 changes: 8 additions & 0 deletions python/vyos/utils/system.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,3 +139,11 @@ def get_load_averages():
res[15] = float(matches["fifteen"]) / core_count

return res

def get_secure_boot_state() -> bool:
from vyos.utils.process import cmd
from vyos.utils.boot import is_uefi_system
if not is_uefi_system():
return False
tmp = cmd('mokutil --sb-state')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line throws an exception for devices that do not support secure-boot. should this be wrapped in a try?

# show ver
Traceback (most recent call last):
  File "/usr/libexec/vyos/op_mode/version.py", line 91, in <module>
    res = vyos.opmode.run(sys.modules[__name__])
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/vyos/opmode.py", line 271, in run
    res = func(**args)
          ^^^^^^^^^^^^
  File "/usr/libexec/vyos/op_mode/version.py", line 81, in show
    version_data = _get_raw_data(funny=funny)
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/libexec/vyos/op_mode/version.py", line 67, in _get_raw_data
    if get_secure_boot_state():
       ^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/vyos/utils/system.py", line 148, in get_secure_boot_state
    tmp = cmd('mokutil --sb-state')
          ^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/usr/lib/python3/dist-packages/vyos/utils/process.py", line 155, in cmd
    raise OSError(code, feedback)
OSError: [Errno 255] failed to run command: mokutil --sb-state
returned:
exit code: 255

# mokutil --sb-state
This system doesn't support Secure Boot

return bool('enabled' in tmp)
3 changes: 3 additions & 0 deletions src/etc/sudoers.d/vyos
Original file line number Diff line number Diff line change
Expand Up @@ -57,4 +57,7 @@ Cmnd_Alias KEA_IP6_ROUTES = /sbin/ip -6 route replace *,\
# Allow members of group sudo to execute any command
%sudo ALL=NOPASSWD: ALL

# Allow any user to query Machine Owner Key status
%sudo ALL=NOPASSWD: /usr/bin/mokutil

_kea ALL=NOPASSWD: KEA_IP6_ROUTES
50 changes: 50 additions & 0 deletions src/op_mode/secure_boot.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#!/usr/bin/env python3
#
# Copyright (C) 2024 VyOS maintainers and contributors
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 or later as
# published by the Free Software Foundation.
#
# This program 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 this program. If not, see <http://www.gnu.org/licenses/>.

import sys
import vyos.opmode

from vyos.utils.boot import is_uefi_system
from vyos.utils.system import get_secure_boot_state

def _get_raw_data(name=None):
sb_data = {
'state' : get_secure_boot_state(),
'uefi' : is_uefi_system()
}
return sb_data

def _get_formatted_output(raw_data):
if not raw_data['uefi']:
print('System run in legacy BIOS mode!')
state = 'enabled' if raw_data['state'] else 'disabled'
return f'SecureBoot {state}'

def show(raw: bool):
sb_data = _get_raw_data()
if raw:
return sb_data
else:
return _get_formatted_output(sb_data)

if __name__ == "__main__":
try:
res = vyos.opmode.run(sys.modules[__name__])
if res:
print(res)
except (ValueError, vyos.opmode.Error) as e:
print(e)
sys.exit(1)
9 changes: 9 additions & 0 deletions src/op_mode/version.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@
import vyos.version
import vyos.limericks

from vyos.utils.boot import is_uefi_system
from vyos.utils.system import get_secure_boot_state

from jinja2 import Template

version_output_tmpl = """
Expand All @@ -43,6 +46,7 @@
Architecture: {{system_arch}}
Boot via: {{boot_via}}
System type: {{system_type}}
Secure Boot: {{secure_boot}}

Hardware vendor: {{hardware_vendor}}
Hardware model: {{hardware_model}}
Expand All @@ -57,6 +61,11 @@

def _get_raw_data(funny=False):
version_data = vyos.version.get_full_version_data()
version_data["secure_boot"] = "n/a (BIOS)"
if is_uefi_system():
version_data["secure_boot"] = "disabled"
if get_secure_boot_state():
version_data["secure_boot"] = "enabled"

if funny:
version_data["limerick"] = vyos.limericks.get_random()
Expand Down
Loading