Skip to content

Commit

Permalink
Support for unified kernels and signing them
Browse files Browse the repository at this point in the history
  • Loading branch information
jackpot51 committed Mar 14, 2023
1 parent 851230b commit 34b27e6
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 21 deletions.
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

0 comments on commit 34b27e6

Please sign in to comment.