Last active
July 1, 2022 22:06
-
-
Save chronos-tachyon/cfd312e9d0986890fcaa3da3ba0cb3b7 to your computer and use it in GitHub Desktop.
Python script for automatically running vmware-modconfig and signing the result for UEFI SecureBoot.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
import argparse | |
import os | |
import subprocess | |
import sys | |
from pathlib import Path | |
MOK_DIR = Path('/var/lib/shim-signed/mok') | |
MOK_DER = MOK_DIR / 'MOK.der' | |
MOK_PRIV = MOK_DIR / 'MOK.priv' | |
MAGIC = b'~Module signature appended~\n' | |
MAGIC_SIZE = len(MAGIC) | |
MODULE_NAMES = ['vmmon', 'vmnet'] | |
def is_secureboot_enabled(): | |
p = subprocess.run(['mokutil', '--sb-state'], stdout=subprocess.PIPE, stderr=subprocess.DEVNULL) | |
return (p.returncode == 0 and p.stdout == b'SecureBoot enabled\n') | |
def run(argv, check=True): | |
argv = list(map(str, argv)) | |
print(f'+ {argv!r}', file=sys.stderr) | |
p = subprocess.run(argv) | |
print(f'+ rc={p.returncode}', file=sys.stderr) | |
if p.returncode == 0: | |
return True | |
elif check: | |
sys.exit(1) | |
else: | |
return False | |
def main(args): | |
os.environ.pop('DISPLAY', None) | |
for key in os.environ: | |
if key.startswith('LC_'): | |
del os.environ[key] | |
os.environ['PATH'] = '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' | |
os.environ['TZ'] = 'America/Los_Angeles' | |
os.environ['LANG'] = 'en_US.UTF-8' | |
os.umask(0o022) | |
HAS_MOK = MOK_PRIV.exists() | |
IS_SECUREBOOT = is_secureboot_enabled() | |
uname = os.uname() | |
KERNEL_VERSION = uname.release | |
SIGN_SCRIPT = Path(f'/usr/src/linux-headers-{KERNEL_VERSION}/scripts/sign-file') | |
MODULE_ROOT = Path(f'/lib/modules/{KERNEL_VERSION}') | |
MODULE_MISC = MODULE_ROOT / 'misc' | |
MODULE_FILENAMES = [name + '.ko' for name in MODULE_NAMES] | |
MODULE_FILES = [MODULE_MISC / filename for filename in MODULE_FILENAMES] | |
if args.force_sign and not HAS_MOK: | |
print('MOK does not exist, --force-sign will not work.') | |
print('You will need to run update-secureboot-policy to create and enroll a MOK.') | |
sys.exit(1) | |
need_build = args.force or args.force_build | |
need_sign = args.force or args.force_sign | |
for module_file in MODULE_FILES: | |
if not module_file.exists(): | |
print(f'module {module_file} does not exist yet', file=sys.stderr) | |
need_build = True | |
need_sign = True | |
continue | |
if HAS_MOK: | |
with open(module_file, 'rb', buffering=0) as fp: | |
fp.seek(-MAGIC_SIZE, os.SEEK_END) | |
magic = fp.read(MAGIC_SIZE) | |
if magic != MAGIC: | |
print(f'module {module_file} is not signed yet', file=sys.stderr) | |
need_sign = True | |
continue | |
if need_build: | |
if not run(['vmware-modconfig', '--console', '--install-all'], check=False): | |
if IS_SECUREBOOT: | |
print('It\'s normal for vmware-modconfig to fail when SecureBoot is enabled.') | |
else: | |
sys.exit(1) | |
if HAS_MOK and need_sign: | |
for module_file in MODULE_FILES: | |
run([SIGN_SCRIPT, 'sha256', MOK_PRIV, MOK_DER, module_file]) | |
if need_build or need_sign or args.force: | |
run(['update-initramfs', '-k', KERNEL_VERSION, '-c']) | |
run(['update-grub']) | |
if IS_SECUREBOOT: | |
print('You will probably need to reboot before you can run VMWare.') | |
print('If you have tried rebooting, verify that your MOK is enrolled.') | |
else: | |
print('If you are running this script manually, you may also need to run:\n' | |
'\tsystemctl restart vmware') | |
if __name__ == '__main__': | |
parser = argparse.ArgumentParser() | |
parser.add_argument('-f', '--force', action='store_true') | |
parser.add_argument('-S', '--force-sign', action='store_true') | |
parser.add_argument('-B', '--force-build', action='store_true') | |
main(parser.parse_args()) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment