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

User Controlled Secure Boot #58

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
14 changes: 14 additions & 0 deletions bin/kernelstub
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def main(options=None): # Do the thing
description = "Automatic Kernel EFIstub manager")
loader_stub = parser.add_mutually_exclusive_group()
install_loader = parser.add_mutually_exclusive_group()
install_unified = parser.add_mutually_exclusive_group()

parser.add_argument(
'-c',
Expand Down Expand Up @@ -188,6 +189,19 @@ def main(options=None): # Do the thing
help = 'Turns off creating loader configuration'
)

install_unified.add_argument(
'--unified',
action = 'store_true',
dest = 'setup_unified',
help = 'Creates a unified kernel executable'
)
install_unified.add_argument(
'--no-unified',
action = 'store_true',
dest = 'off_unified',
help = 'Turns off creating unified kernel executable'
)

loader_stub.add_argument(
'-s',
'--stub',
Expand Down
55 changes: 39 additions & 16 deletions kernelstub/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,11 @@ def main(self, args): # Do the thing
if args.off_loader:
configuration['setup_loader'] = False

if args.setup_unified:
configuration['unified_kernel'] = True
if args.off_unified:
configuration['unified_kernel'] = False

if args.install_stub:
configuration['manage_mode'] = False
if args.manage_mode:
Expand Down Expand Up @@ -316,6 +321,7 @@ def main(self, args): # Do the thing
' ESP Location:..................%s\n' % configuration['esp_path'] +
' Management Mode:...............%s\n' % configuration['manage_mode'] +
' Install Loader configuration:..%s\n' % configuration['setup_loader'] +
' Unified kernel:................%s\n' % configuration['unified_kernel'] +
' Configuration version:.........%s\n' % configuration['config_rev'])
log.info('Configuration details: \n\n%s' % all_config)
exit(0)
Expand All @@ -325,25 +331,42 @@ def main(self, args): # Do the thing
kopts = 'root=UUID=%s ro %s' % (drive.root_uuid, " ".join(kernel_opts))
log.debug('kopts: %s' % kopts)



installer.setup_kernel(
kopts,
setup_loader=setup_loader,
overwrite=force,
simulate=no_run)
try:
installer.backup_old(
if configuration['unified_kernel']:
installer.setup_unified_kernel(
kopts,
old=False,
overwrite=force,
simulate=no_run
)
try:
installer.setup_unified_kernel(
kopts,
old=True,
overwrite=force,
simulate=no_run)
except Exception as e:
log.debug('Couldn\'t back up old kernel. \nThis might just mean ' +
'You don\'t have an old kernel installed. If you do, try ' +
'with -vv to see debuging information')
log.debug(e)
else:
installer.setup_kernel(
kopts,
setup_loader=setup_loader,
overwrite=force,
simulate=no_run)
except Exception as e:
log.debug('Couldn\'t back up old kernel. \nThis might just mean ' +
'You don\'t have an old kernel installed. If you do, try ' +
'with -vv to see debuging information')
log.debug(e)

installer.copy_cmdline(simulate=no_run)
try:
installer.backup_old(
kopts,
setup_loader=setup_loader,
simulate=no_run)
except Exception as e:
log.debug('Couldn\'t back up old kernel. \nThis might just mean ' +
'You don\'t have an old kernel installed. If you do, try ' +
'with -vv to see debuging information')
log.debug(e)

installer.copy_cmdline(simulate=no_run)

if not manage_mode:
installer.setup_stub(kopts, simulate=no_run)
Expand Down
12 changes: 8 additions & 4 deletions kernelstub/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ class Config():
'manage_mode': False,
'force_update' : False,
'live_mode' : False,
'config_rev' : 3
'unified_kernel': False,
'config_rev' : 4
}
}

Expand Down Expand Up @@ -107,7 +108,7 @@ def save_config(self, path='/etc/kernelstub/configuration'):

with open(path, mode='w') as config_file:
json.dump(self.config, config_file, indent=2)

self.log.debug('Configuration saved!')
return 0

Expand All @@ -120,8 +121,11 @@ def update_config(self, config):
config['user']['kernel_options'] = self.parse_options(config['user']['kernel_options'].split())
if type(config['default']['kernel_options']) is str:
config['default']['kernel_options'] = self.parse_options(config['default']['kernel_options'].split())
config['user']['config_rev'] = 3
config['default']['config_rev'] = 3
if config['user']['config_rev'] < 4:
config['user']['unified_kernel'] = False
config['default']['unified_kernel'] = False
config['user']['config_rev'] = 4
config['default']['config_rev'] = 4
return config

def parse_options(self, options):
Expand Down
79 changes: 78 additions & 1 deletion kernelstub/installer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
terms.
"""

import os, shutil, logging, platform, gzip
import os, shutil, logging, platform, gzip, subprocess

from pathlib import Path

Expand Down Expand Up @@ -58,6 +58,83 @@ def __init__(self, nvram, opsys, drive):
if not os.path.exists(self.entry_dir):
os.makedirs(self.entry_dir)

def setup_unified_kernel(self, kernel_opts, old=False, overwrite=False, simulate=False):
if old:
suffix = 'previous'
kernel_path = self.opsys.old_kernel_path
initrd_path = self.opsys.old_initrd_path
else:
suffix = 'current'
kernel_path = self.opsys.kernel_path
initrd_path = self.opsys.initrd_path

tmp_dir = os.path.join('/tmp/kernelstub', suffix)
self.ensure_dir(tmp_dir, simulate=simulate)

cmdline_path = os.path.join(tmp_dir, 'cmdline')
if simulate:
self.log.info('Simulate creating file: %s with contents %s' % (cmdline_path, kernel_opts))
else:
with open(cmdline_path, mode='w') as f:
f.write(kernel_opts)

self.log.info('Creating unified Linux EFI executable (%s)' % (suffix))
kernel_unsigned_efi_path = os.path.join(tmp_dir, 'linux-unsigned.efi')
objcopy = [
'objcopy',
'--add-section', '.osrel=/usr/lib/os-release', '--change-section-vma', '.osrel=0x20000',
'--add-section', '.cmdline=' + cmdline_path, '--change-section-vma', '.cmdline=0x30000',
'--add-section', '.linux=' + kernel_path, '--change-section-vma', '.linux=0x2000000',
'--add-section', '.initrd=' + initrd_path, '--change-section-vma', '.initrd=0x3000000',
'/usr/lib/systemd/boot/efi/linuxx64.efi.stub', kernel_unsigned_efi_path
]
if simulate:
self.log.info('Simulate running command: %s' % (objcopy))
else:
subprocess.check_call(objcopy)

sign_crt = '/etc/kernelstub/mok.crt'
sign_key = '/etc/kernelstub/mok.key'
if os.path.exists(sign_crt) and os.path.exists(sign_key):
self.log.info('Signing unified Linux EFI executable (%s)' % (suffix))
kernel_signed_efi_path = os.path.join(tmp_dir, 'signed.efi')
sbsign = [
'sbsign',
'--cert', sign_crt,
'--key', sign_key,
'--output', kernel_signed_efi_path,
kernel_unsigned_efi_path
]
if simulate:
self.log.info('Simulate running command: %s' % (sbsign))
else:
subprocess.check_call(sbsign)
kernel_efi_path = kernel_signed_efi_path
else:
kernel_efi_path = kernel_unsigned_efi_path

self.log.info('Copying unified Linux EFI executable to ESP (%s)' % (suffix))
kernel_efi_dest_dir = os.path.join(self.work_dir, 'Linux')
self.ensure_dir(kernel_efi_dest_dir, simulate=simulate)
kernel_efi_name = self.opsys.name + '-' + suffix + '-' + self.drive.root_uuid + '.efi'
kernel_efi_dest = os.path.join(kernel_efi_dest_dir, kernel_efi_name)
self.copy_files(
kernel_efi_path,
kernel_efi_dest,
simulate=simulate
)

if not overwrite and not simulate:
if not os.path.exists('%s/loader.conf' % self.loader_dir):
overwrite = True

if overwrite and not old and not simulate:
self.ensure_dir(self.loader_dir)
with open(
'%s/loader.conf' % self.loader_dir, mode='w') as loader:

default_line = 'default %s\n' % kernel_efi_name
loader.write(default_line)

def backup_old(self, kernel_opts, setup_loader=False, simulate=False):
self.log.info('Backing up old kernel')
Expand Down