diff --git a/bin/ubuntu-core-initramfs b/bin/ubuntu-core-initramfs index 1f6bc512..a5c31a49 100755 --- a/bin/ubuntu-core-initramfs +++ b/bin/ubuntu-core-initramfs @@ -1,7 +1,7 @@ #!/usr/bin/python3 import argparse import os -import subprocess +from subprocess import run, check_call, check_output import tempfile import pathlib import platform @@ -259,7 +259,7 @@ def add_modules_from_file(dest_d, kernel_root, modules_d, fw_d, conf_file, db, if not mod.builtin: db.mark_installed(module, conf_file) - subprocess.check_call( + check_call( [ "/usr/lib/dracut/dracut-install", "-D", @@ -276,7 +276,194 @@ def add_modules_from_file(dest_d, kernel_root, modules_d, fw_d, conf_file, db, ) +def install_files(files, dest_dir): + proc_env = os.environ.copy() + proc_env["LD_PRELOAD"] = "" + check_call( + [ + "/usr/lib/dracut/dracut-install", + "-D", dest_dir, + "--ldd", "--all", + ] + files, + env=proc_env) + + +# This is useful if the destination path inside dest_dir is different +# from the current file path. +def install_file_to_path(file, dest_dir, dest_path): + proc_env = os.environ.copy() + proc_env["LD_PRELOAD"] = "" + check_call( + [ + "/usr/lib/dracut/dracut-install", + "-D", dest_dir, + "--ldd", file, dest_path, + ], + env=proc_env) + + +# Returns as a list the files contained in a list of deb packages. +def package_files(pkgs): + out = check_output(["dpkg", "-L"] + pkgs) + return out.decode("utf-8").splitlines() + + +def install_systemd_files(dest_dir): + # Build list of files and directories + + lines = package_files(["systemd", "systemd-sysv"]) + # From systemd, we pull + # * units configuration + # * Executables + # * Module load options + # * Configuration of kernel parameters + # * udev rules + # * Configuration for systemd-tmpfiles + # TODO: some of this can be cleaned up + to_include = re.compile(r"^/lib/systemd/system|" + r".*/modprobe\.d/|" + r".*/sysctl\.d/|" + r".*/rules\.d/|" + r".*/tmpfiles\.d/|" + r".*bin/|" + r".*sbin/" + ) + files = [i for i in lines if to_include.match(i)] + + lines = package_files(["udev"]) + # From udev, we pull + # * Executables + # * systemd configuration (units, tmpfiles) + # * udev rules + # * hwdb + # TODO: some of this can be cleaned up + to_include = re.compile(r".*bin/|" + r".*lib/|" + r".*rules\.d/" + ) + files += [i for i in lines if to_include.match(i)] + + files.append("/var/lib/systemd/") + + # Filter out some units we don't want + to_remove = re.compile(".*systemd-gpt-auto-generator|" + ".*proc-sys-fs-binfmt_misc.automount|" + ".*systemd-pcrphase.*") + filtered = [i for i in files if not to_remove.match(i)] + # Install + install_files(filtered, dest_dir) + + # Local modifications + # This hack should be removed with PR#113 + check_call([r"sed -i '/^After=/" + r"{;s, *plymouth-start[.]service *, ,;/" + r"^After= *$/d;}' " + + os.path.join(dest_dir, + "usr/lib/systemd/system/systemd-ask-password-*")], + shell=True) + # Generate hw database (/usr/lib/udev/hwdb.bin) for udev and + # remove redundant definitions after that. + check_call(["systemd-hwdb", "--root", dest_dir, + "update", "--usr", "--strict"]) + shutil.rmtree(os.path.join(dest_dir, "usr/lib/udev/hwdb.d")) + + +def install_busybox(dest_dir): + install_file_to_path("/usr/lib/initramfs-tools/bin/busybox", dest_dir, + "usr/bin/busybox") + # Create links to commands + bb_cmd = os.path.join(dest_dir, "usr/bin/busybox") + out = check_output([bb_cmd, "--list-long"]) + cmds = out.decode("utf-8").splitlines() + # Remove commands we do not want + to_remove = ["busybox", "reboot", "mount", "umount", "modinfo"] + cmds = [c for c in cmds if c not in to_remove] + for c in cmds: + os.symlink("busybox", os.path.join(dest_dir, "usr/bin", c)) + + +def install_misc(dest_dir): + # dmsetup rules + rules = package_files(["dmsetup"]) + to_include = re.compile(r".*rules.d/") + rules = [i for i in rules if to_include.match(i)] + install_files(rules, dest_dir) + + # Other needed stuff + out = check_output(["dpkg-architecture", "-q", + "DEB_HOST_MULTIARCH"]).decode("utf-8") + deb_arch = out.splitlines()[0] + files = [ + "/usr/bin/kmod", + "/usr/bin/mount", + "/usr/sbin/sulogin", + "/usr/bin/tar", + "/usr/lib/" + deb_arch + "/libgcc_s.so.1", + "/usr/lib/systemd/system/dbus.service", + "/usr/lib/systemd/system/dbus.socket", + "/usr/lib/systemd/system/plymouth-start.service", + "/usr/lib/systemd/system/plymouth-switch-root.service", + "/usr/lib/systemd/systemd-bootchart", + "/usr/sbin/cryptsetup", + "/usr/sbin/dmsetup", + "/usr/sbin/e2fsck", + "/usr/sbin/fsck", + "/usr/bin/umount", + "/usr/sbin/fsck.vfat", + "/usr/sbin/fsck.vfat", + "/usr/sbin/mkfs.ext4", + "/usr/sbin/mkfs.vfat", + "/usr/sbin/sfdisk", + "/usr/bin/dbus-daemon", + "/usr/bin/mountpoint", + "/usr/bin/partx", + "/usr/bin/plymouth", + "/usr/bin/unsquashfs", + "/usr/lib/" + deb_arch + "/plymouth/label-ft.so", + "/usr/lib/" + deb_arch + "/plymouth/script.so", + "/usr/lib/" + deb_arch + "/plymouth/two-step.so", + "/usr/sbin/depmod", + "/usr/sbin/insmod", + "/usr/sbin/lsmod", + "/usr/sbin/modinfo", + "/usr/sbin/modprobe", + "/usr/sbin/plymouthd", + "/usr/sbin/rmmod", + "/usr/share/dbus-1/system.conf", + "/usr/share/libdrm/amdgpu.ids", + ] + files += glob.glob("/lib/" + deb_arch + "/libnss_compat.so.*") + files += glob.glob("/lib/" + deb_arch + "/libnss_files.so.*") + files += glob.glob("/usr/lib/" + deb_arch + "/plymouth/renderers/*.so") + files += glob.glob("/usr/share/plymouth/themes/bgrt/*") + files += glob.glob("/usr/share/plymouth/themes/spinner/*") + install_files(files, dest_dir) + # Links for fsck + os.symlink("e2fsck", os.path.join(dest_dir, "usr/sbin", "fsck.ext4")) + # Get deps for shared objects that have not the exec bit set and that + # are loaded with dlopen (which means that they are not pull by --ldd + # option, instead use --resolvelazy). + proc_env = os.environ.copy() + proc_env["LD_PRELOAD"] = "" + to_resolve = [ + "/usr/lib/" + deb_arch + "/plymouth/label-ft.so", + "/usr/lib/" + deb_arch + "/plymouth/script.so", + "/usr/lib/" + deb_arch + "/plymouth/two-step.so", + ] + to_resolve += glob.glob("/usr/lib/" + deb_arch + "/plymouth/renderers/*.so") + check_call( + [ + "/usr/lib/dracut/dracut-install", + "-D", dest_dir, + "--resolvelazy", + ] + to_resolve, + env=proc_env) + # Build ld cache + check_call(["ldconfig", "-r", dest_dir]) + + def create_initrd(parser, args): + # TODO generate microcode instead of shipping in debian package rootfs = "/" if not args.kerneldir: args.kerneldir = "/lib/modules/%s" % args.kernelver @@ -293,49 +480,48 @@ def create_initrd(parser, args): modules = os.path.join(kernel_root, "usr", "lib", "modules") os.makedirs(modules, exist_ok=True) modules = os.path.join(modules, args.kernelver) - subprocess.check_call(["cp", "-ar", args.kerneldir, modules]) + check_call(["cp", "-ar", args.kerneldir, modules]) firmware = os.path.join(kernel_root, "usr", "lib", "firmware") - subprocess.check_call(["cp", "-ar", args.firmwaredir, firmware]) + check_call(["cp", "-ar", args.firmwaredir, firmware]) db = ModuleDb(modules) main = os.path.join(d, "main") os.makedirs(main, exist_ok=True) + # copy busybox first so we get already the shell interpreter we + # want (busybox) instead of dracut-install pulling the systemd + # default (dash) when it pulls a shell script later. + install_busybox(main) + # Copy systemd bits + install_systemd_files(main) + # Other miscelanea stuff + install_misc(main) # Copy snapd bits snapd_lib = path_join_make_rel_paths(rootfs, "/usr/lib/snapd") snapd_files = [os.path.join(snapd_lib, "snap-bootstrap"), os.path.join(snapd_lib, "info"), "/lib/systemd/system/snapd.recovery-chooser-trigger.service"] - for snapd_f in snapd_files: - subprocess.check_call( - [ - "/usr/lib/dracut/dracut-install", - "-D", main, - "--ldd", snapd_f, - ] - ) + install_files(snapd_files, main) # Copy features for feature in args.features: # Add feature files feature_path = os.path.join(args.skeleton, feature) if os.path.isdir(feature_path): - subprocess.check_call(["cp", "-aT", feature_path, main]) + check_call(["cp", "-aT", feature_path, main]) # Add feature kernel modules extra_modules = os.path.join(args.skeleton, "modules", feature, "extra-modules.conf") if os.path.exists(extra_modules): add_modules_from_file(main, kernel_root, modules, firmware, extra_modules, db) + # TODO xnox: fips actually needs additional runtime dependencies than + # this, and currently forked in fips PPA. we need to figure out how to + # make ubuntu-core-initramfs-fips a reality. if "fips" in args.features: - subprocess.check_call( - [ - "/usr/lib/dracut/dracut-install", - "-D", main, - "--ldd", "--all", + install_files([ "/usr/bin/kcapi-hasher", "/usr/bin/.kcapi-hasher.hmac", - ] + glob.glob("/usr/lib/*/.libkcapi.so.*.hmac") - ) + ] + glob.glob("/usr/lib/*/.libkcapi.so.*.hmac"), main) # Update epoch pathlib.Path("%s/main/usr/lib/clock-epoch" % d).touch() @@ -345,7 +531,7 @@ def create_initrd(parser, args): warn_discoverable=True) for modulesf in ["modules.order", "modules.builtin", "modules.builtin.bin", "modules.builtin.modinfo"]: - subprocess.check_call( + check_call( [ "/usr/lib/dracut/dracut-install", "-D", @@ -355,13 +541,13 @@ def create_initrd(parser, args): os.path.join("usr/lib/modules", args.kernelver, modulesf), ] ) - subprocess.check_call(["depmod", "-a", "-b", main, args.kernelver]) + check_call(["depmod", "-a", "-b", main, args.kernelver]) with open(args.output, "wb") as output: for early in glob.iglob("%s/early/*.cpio" % args.skeleton): with open(early, "rb") as f: shutil.copyfileobj(f, output) output.write( - subprocess.run( + run( "find . | cpio --create --quiet --format='newc' --owner=0:0 | zstd -1 -T0", cwd=main, capture_output=True, @@ -387,7 +573,7 @@ def create_efi(parser, args): if platform.machine() == "aarch64": import gzip - raw_kernel=tempfile.NamedTemporaryFile(mode='wb') + raw_kernel = tempfile.NamedTemporaryFile(mode='wb') try: with gzip.open(args.kernel, 'rb') as comp_kernel: shutil.copyfileobj(comp_kernel, raw_kernel) @@ -424,9 +610,9 @@ def create_efi(parser, args): args.stub, args.output, ] - subprocess.check_call(objcopy_cmd) + check_call(objcopy_cmd) if not args.unsigned: - subprocess.check_call( + check_call( [ "sbsign", "--key", @@ -442,7 +628,7 @@ def create_efi(parser, args): def main(): - kernelver = subprocess.check_output( + kernelver = check_output( ["uname", "-r"], universal_newlines=True ).strip() suffix = {"x86_64": "x64", @@ -459,7 +645,7 @@ def main(): efi_parser.add_argument("--stub", help="path to stub") if suffix: efi_parser.set_defaults( - stub="/usr/lib/ubuntu-core-initramfs/efi/linux%s.efi.stub" % suffix + stub="/usr/lib/systemd/boot/efi/linux%s.efi.stub" % suffix ) efi_parser.add_argument("--kernel", help="path to kernel", default="/boot/vmlinuz") efi_parser.add_argument( @@ -511,7 +697,7 @@ def main(): "--output", help="path to output", default="/boot/ubuntu-core-initramfs.img" ) initrd_parser.set_defaults( - kernelver=subprocess.check_output( + kernelver=check_output( ["uname", "-r"], universal_newlines=True ).strip() ) diff --git a/debian/control b/debian/control index 8455b05e..39473b4f 100644 --- a/debian/control +++ b/debian/control @@ -2,37 +2,49 @@ Source: ubuntu-core-initramfs Section: utils Priority: optional Maintainer: Dimitri John Ledkov -Build-Depends: debhelper-compat (= 13), dh-python, python3:any, dracut-core, busybox-initramfs, +Build-Depends: debhelper-compat (= 13), dh-python, amd64-microcode [amd64], - dbus, - dmsetup, - dosfstools, - e2fsprogs, + cpio, fakeroot, - fdisk, fonts-ubuntu, - git, - intel-microcode [amd64], - kmod, - libgcc-s1, - mount, - plymouth-label-ft, - plymouth-theme-spinner, - squashfs-tools, - systemd, - systemd-boot-efi, - systemd-bootchart, - cryptsetup-bin, - systemd-sysv, - tar, - udev, - util-linux + intel-microcode [amd64] Standards-Version: 4.4.1 Homepage: https://launchpad.net/ubuntu-core-initramfs Package: ubuntu-core-initramfs Architecture: amd64 arm64 armhf riscv64 -Depends: ${python3:Depends}, ${misc:Depends}, dracut-core (>= 051-1), zstd, sbsigntool, snapd (>= 2.50+20.04), linux-firmware, llvm, kcapi-tools (>= 1.4.0-1ubuntu3) +Depends: ${python3:Depends}, ${misc:Depends}, dracut-core (>= 051-1), + python3:any, + dracut-core, + busybox-initramfs, + zstd, + sbsigntool, + snapd (>= 2.50+20.04), + linux-firmware, + llvm, + kcapi-tools (>= 1.4.0-1ubuntu3), + dbus, + dmsetup, + dosfstools, + dpkg-dev, + e2fsprogs, + fakeroot, + fdisk, + git, + kmod, + libgcc-s1, + mount, + plymouth-label-ft, + plymouth-theme-spinner, + squashfs-tools, + systemd, + systemd-boot-efi, + systemd-bootchart, + cryptsetup-bin, + systemd-sysv, + tar, + udev, + util-linux Description: standard embedded initrd Standard embedded initrd implementation to be used with Ubuntu Core systems. Currently targetting creating BLS Type2 like binaries. diff --git a/debian/install b/debian/install index 118ab793..7f37d569 100644 --- a/debian/install +++ b/debian/install @@ -2,6 +2,5 @@ bin/ubuntu-core-initramfs usr/bin postinst.d etc/kernel/ snakeoil/* usr/lib/ubuntu-core-initramfs/snakeoil/ debian/tmp/* usr/lib/ubuntu-core-initramfs/main -debian/tmp-efi/* usr/lib/ubuntu-core-initramfs/efi/ modules usr/lib/ubuntu-core-initramfs/ fips usr/lib/ubuntu-core-initramfs/ diff --git a/debian/rules b/debian/rules index 8e454b7a..6da56309 100755 --- a/debian/rules +++ b/debian/rules @@ -6,55 +6,10 @@ include /usr/share/dpkg/default.mk %: dh $@ -INSTALL_FILES_FROM_HOST= \ - /bin/kmod \ - /bin/mount \ - /sbin/sulogin \ - /bin/tar \ - /lib/$(DEB_HOST_MULTIARCH)/libgcc_s.so.1 \ - /lib/$(DEB_HOST_MULTIARCH)/libnss_compat.so.* \ - /lib/$(DEB_HOST_MULTIARCH)/libnss_files.so.* \ - /lib/systemd/system/dbus.service \ - /lib/systemd/system/dbus.socket \ - /lib/systemd/system/plymouth-start.service \ - /lib/systemd/system/plymouth-switch-root.service \ - /lib/systemd/systemd-bootchart \ - /sbin/cryptsetup \ - /sbin/dmsetup \ - /sbin/e2fsck \ - /sbin/fsck /bin/umount \ - /sbin/fsck.vfat \ - /sbin/fsck.vfat \ - /sbin/mkfs.ext4 \ - /sbin/mkfs.vfat \ - /sbin/sfdisk \ - /usr/bin/dbus-daemon \ - /usr/bin/mountpoint \ - /usr/bin/partx \ - /usr/bin/plymouth \ - /usr/bin/unsquashfs \ - /usr/lib/$(DEB_HOST_MULTIARCH)/plymouth/label-ft.so \ - /usr/lib/$(DEB_HOST_MULTIARCH)/plymouth/renderers/*.so \ - /usr/lib/$(DEB_HOST_MULTIARCH)/plymouth/script.so \ - /usr/lib/$(DEB_HOST_MULTIARCH)/plymouth/two-step.so \ - /usr/sbin/depmod \ - /usr/sbin/insmod \ - /usr/sbin/lsmod \ - /usr/sbin/modinfo \ - /usr/sbin/modprobe \ - /usr/sbin/plymouthd \ - /usr/sbin/rmmod \ - /usr/share/dbus-1/system.conf \ - /usr/share/libdrm/amdgpu.ids \ - /usr/share/plymouth/themes/bgrt/* \ - /usr/share/plymouth/themes/spinner/* - override_dh_auto_install: - rm -rf debian/tmp debian/tmp-efi - mkdir debian/tmp debian/tmp-efi + rm -rf debian/tmp + mkdir debian/tmp cp -ar factory/* debian/tmp - mkdir -p debian/tmp/usr/bin - mkdir -p debian/tmp/usr/lib64 # splash functionality mkdir -p debian/tmp/usr/share/plymouth/themes/ @@ -66,61 +21,9 @@ override_dh_auto_install: touch debian/tmp/etc/machine-id - # Include all needed systemd bits - set -e; \ - for f in $$(dpkg -L systemd | \ - grep -E '(^/lib/systemd/system|/modprobe\.d/|/sysctl\.d/|/rules\.d/|/tmpfiles\.d/|/bin/)') \ - $$(dpkg -L systemd-sysv | grep sbin/) \ - /var/lib/systemd/ \ - $$(dpkg -L udev | grep -E '(bin/|lib/|rules\.d/)') \ - ; \ - do \ - LD_PRELOAD= \ - /usr/lib/dracut/dracut-install \ - -D $(CURDIR)/debian/tmp --ldd $$f; \ - done - # But we don't won't to automount the rootfs - rm -f --verbose debian/tmp/usr/lib/systemd/system-generators/systemd-gpt-auto-generator - # or this (binfmt_misc module is not in the initramfs) - rm debian/tmp/usr/lib/systemd/system/sysinit.target.wants/proc-sys-fs-binfmt_misc.automount - # Remove all pcrphase related bits for the moment (services and binary) - find debian/tmp/ -type f,l -name \*systemd-pcrphase\* -delete - - # This hack should be removed with #113 - sed -i '/^After=/{;s, *plymouth-start[.]service *, ,;/^After= *$$/d;}' debian/tmp/usr/lib/systemd/system/systemd-ask-password-* - - # Generate hw database (/usr/lib/udev/hwdb.bin) for udev and - # remove redundant definitions after that. - systemd-hwdb --root debian/tmp update --usr --strict - rm -rf debian/tmp/usr/lib/udev/hwdb.d - - # Use busybox shell instead of dash as in the past - rm debian/tmp/usr/bin/sh debian/tmp/usr/bin/dash - /usr/lib/dracut/dracut-install -D $(CURDIR)/debian/tmp --ldd /usr/lib/initramfs-tools/bin/busybox usr/bin/busybox - set -e; \ - for alias in `debian/tmp/usr/bin/busybox --list-long | grep -v -e busybox -e reboot -e mount -e umount`; do \ - ln -v -s busybox debian/tmp/usr/bin/$$alias; \ - done - - LD_PRELOAD= /usr/lib/dracut/dracut-install -D $(CURDIR)/debian/tmp --ldd $(INSTALL_FILES_FROM_HOST) - dpkg -L dmsetup | grep rules.d | xargs -L1 /usr/lib/dracut/dracut-install -D $(CURDIR)/debian/tmp --ldd - ln -v -s e2fsck debian/tmp/usr/sbin/fsck.ext4 - - set -e; \ - for e in $$(find debian/tmp -type f -executable) \ - /usr/lib/$(DEB_HOST_MULTIARCH)/plymouth/*.so \ - /usr/lib/$(DEB_HOST_MULTIARCH)/plymouth/renderers/*.so; do \ - LD_PRELOAD= \ - /usr/lib/dracut/dracut-install -D $(CURDIR)/debian/tmp --resolvelazy $$e ; \ - done - ldconfig -r debian/tmp - - # Include stub (used when building kernel.efi) - install /usr/lib/systemd/boot/efi/linux*.efi.stub $(CURDIR)/debian/tmp-efi/ - override_dh_install: dh_install - rm -rf debian/ubuntu-core-initramfs/usr/lib/ubuntu-core-initramfs/main/usr/lib/systemd/boot + ifeq ($(DEB_HOST_ARCH),amd64) mkdir -p debian/ubuntu-core-initramfs/usr/lib/ubuntu-core-initramfs/early/ debian/generate-x86-microcode debian/ubuntu-core-initramfs/usr/lib/ubuntu-core-initramfs/early/microcode.cpio diff --git a/factory/bin b/factory/bin deleted file mode 120000 index 1e881eda..00000000 --- a/factory/bin +++ /dev/null @@ -1 +0,0 @@ -usr/bin \ No newline at end of file diff --git a/factory/lib b/factory/lib deleted file mode 120000 index 0d5487ba..00000000 --- a/factory/lib +++ /dev/null @@ -1 +0,0 @@ -usr/lib \ No newline at end of file diff --git a/factory/lib64 b/factory/lib64 deleted file mode 120000 index d4801c6b..00000000 --- a/factory/lib64 +++ /dev/null @@ -1 +0,0 @@ -usr/lib64 \ No newline at end of file diff --git a/factory/sbin b/factory/sbin deleted file mode 120000 index 1e881eda..00000000 --- a/factory/sbin +++ /dev/null @@ -1 +0,0 @@ -usr/bin \ No newline at end of file diff --git a/factory/usr/sbin b/factory/usr/sbin deleted file mode 120000 index c5e82d74..00000000 --- a/factory/usr/sbin +++ /dev/null @@ -1 +0,0 @@ -bin \ No newline at end of file