diff --git a/kernelstub/application.py b/kernelstub/application.py index 9ffe4be..b50875f 100755 --- a/kernelstub/application.py +++ b/kernelstub/application.py @@ -316,6 +316,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) @@ -325,25 +326,40 @@ 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, + simulate=no_run + ) + try: + installer.setup_unified_kernel( + kopts, + old=True, + 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) diff --git a/kernelstub/config.py b/kernelstub/config.py index b2c3ed9..de555ff 100644 --- a/kernelstub/config.py +++ b/kernelstub/config.py @@ -39,7 +39,8 @@ class Config(): 'manage_mode': False, 'force_update' : False, 'live_mode' : False, - 'config_rev' : 3 + 'unified_kernel': False, + 'config_rev' : 4 } } @@ -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 @@ -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): diff --git a/kernelstub/installer.py b/kernelstub/installer.py index 59b66fa..bf635c6 100644 --- a/kernelstub/installer.py +++ b/kernelstub/installer.py @@ -22,7 +22,7 @@ terms. """ -import os, shutil, logging, platform, gzip +import os, shutil, logging, platform, gzip, subprocess from pathlib import Path @@ -58,6 +58,71 @@ 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, 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/db.crt' + sign_key = '/etc/kernelstub/db.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 + ) def backup_old(self, kernel_opts, setup_loader=False, simulate=False): self.log.info('Backing up old kernel')