diff --git a/flake.nix b/flake.nix
index f1005dc..5b1774f 100644
--- a/flake.nix
+++ b/flake.nix
@@ -59,7 +59,7 @@
                 { drv = pkgs.binutils-unwrapped; path = "bin/strings"; }
                 { drv = pkgs.strace; path = "bin/strace"; }
                 { drv = patosPkgs.tpm2-tools; path = "bin/tpm2"; }
-                { drv = patosPkgs.openssl; path = "usr/bin/openssl"; destpath = "bin/openssl"; }
+                { drv = patosPkgs.openssl; path = "bin/openssl"; }
                 { drv = pkgs.cryptsetup; path = "bin/cryptsetup"; }
                 { drv = pkgs.cryptsetup; path = "bin/veritysetup"; }
                 { drv = pkgs.erofs-utils; path = "bin/mkfs.erofs"; }
diff --git a/pkgs/image/default.nix b/pkgs/image/default.nix
index 0fcaf3f..74e0931 100644
--- a/pkgs/image/default.nix
+++ b/pkgs/image/default.nix
@@ -7,12 +7,10 @@
 }:
 let
   pname = "patos-image";
-  defaultPassword = "patos";
 in
 stdenvNoCC.mkDerivation (finalAttrs: {
   inherit version;
   inherit pname;
-  inherit defaultPassword;
 
   buildInputs = with pkgs; [
     erofs-utils
@@ -29,7 +27,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
   };
 
   systemd = patosPkgs.systemd.out;
-  kernel = patosPkgs.kernel.kernel;
+  kernel = patosPkgs.kernel;
   initrd = patosPkgs.initrd.out;
   rootfs = patosPkgs.rootfs.out;
 
diff --git a/pkgs/image/mkimage.sh b/pkgs/image/mkimage.sh
index 78e55f8..df56849 100644
--- a/pkgs/image/mkimage.sh
+++ b/pkgs/image/mkimage.sh
@@ -27,13 +27,6 @@ mv rootfs/usr/lib/systemd/network/89-ethernet.network.example rootfs/usr/lib/sys
 ln -sf ../systemd-confext.service rootfs/usr/lib/systemd/system/sysinit.target.wants/systemd-confext.service
 ln -sf ../systemd-sysext.service rootfs/usr/lib/systemd/system/sysinit.target.wants/systemd-sysext.service
 
-# install sys users
-mkdir creds
-echo -n $defaultPassword > creds/passwd.plaintext-password.root
-CREDENTIALS_DIRECTORY=$PWD/creds SYSTEMD_CRYPT_PREFIX='$6$' $systemd/usr/bin/systemd-sysusers --root=rootfs rootfs/usr/lib/sysusers.d/*.conf
-chmod 600 rootfs/etc/shadow
-rm -rf creds
-
 # Initial partitioning
 cat <<EOF > init.repart.d/10-root.conf
 [Partition]
diff --git a/pkgs/kernel/default.nix b/pkgs/kernel/default.nix
index 73ecd1f..c5dabce 100644
--- a/pkgs/kernel/default.nix
+++ b/pkgs/kernel/default.nix
@@ -1,9 +1,9 @@
-{ pkgs, ... }:
+{ pkgs, lib, stdenv, ... }:
 let
   version = "6.13.4";
 in
-pkgs.linuxPackagesFor (
-  pkgs.linuxManualConfig {
+  (pkgs.callPackage ./manual-config.nix { })  {
+    inherit lib stdenv;
     version = "${version}-patos1";
     modDirVersion = version;
     src = pkgs.fetchurl {
@@ -13,4 +13,3 @@ pkgs.linuxPackagesFor (
     configfile = ./generic.config;
     allowImportFromDerivation = true;
   }
-)
diff --git a/pkgs/kernel/generic.config b/pkgs/kernel/generic.config
index 209e026..647bf91 100644
--- a/pkgs/kernel/generic.config
+++ b/pkgs/kernel/generic.config
@@ -522,11 +522,11 @@ CONFIG_DEBUG_BUGVERBOSE=y
 CONFIG_DEBUG_ENTRY=y
 CONFIG_DEBUG_FS_ALLOW_ALL=y
 CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_INFO_BTF_MODULES=y
-CONFIG_DEBUG_INFO_BTF=y
-CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
-CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
-CONFIG_DEBUG_INFO=y
+#CONFIG_DEBUG_INFO_BTF_MODULES=y
+#CONFIG_DEBUG_INFO_BTF=y
+#CONFIG_DEBUG_INFO_COMPRESSED_NONE=y
+#CONFIG_DEBUG_INFO_DWARF_TOOLCHAIN_DEFAULT=y
+CONFIG_DEBUG_INFO=n
 CONFIG_DEBUG_KERNEL=y
 CONFIG_DEBUG_LIST=y
 CONFIG_DEBUG_MISC=y
@@ -1400,6 +1400,10 @@ CONFIG_MODULE_COMPRESS_ZSTD=y
 CONFIG_MODULE_FORCE_UNLOAD=y
 CONFIG_MODULE_SRCVERSION_ALL=y
 CONFIG_MODULE_UNLOAD=y
+CONFIG_MODULE_SIG=y
+CONFIG_MODULE_SIG_FORCE=n
+CONFIG_MODULE_SIG_ALL=y
+CONFIG_MODULE_SIG_KEY="certs/signing_key.pem"
 CONFIG_MODULES_TREE_LOOKUP=y
 CONFIG_MODULES_USE_ELF_RELA=y
 CONFIG_MODULES=y
diff --git a/pkgs/kernel/manual-config.nix b/pkgs/kernel/manual-config.nix
new file mode 100644
index 0000000..ffcf758
--- /dev/null
+++ b/pkgs/kernel/manual-config.nix
@@ -0,0 +1,465 @@
+{ lib, stdenv, buildPackages, runCommand, nettools, bc, bison, flex, perl, rsync, gmp, libmpc, mpfr, openssl
+, cpio, elfutils, hexdump, zstd, python3Minimal, zlib, pahole, kmod, ubootTools
+, fetchpatch
+, rustc, rust-bindgen, rustPlatform
+}:
+
+let
+  lib_ = lib;
+  stdenv_ = stdenv;
+
+  readConfig = configfile: import (runCommand "config.nix" {} ''
+    echo "{" > "$out"
+    while IFS='=' read key val; do
+      [ "x''${key#CONFIG_}" != "x$key" ] || continue
+      no_firstquote="''${val#\"}";
+      echo '  "'"$key"'" = "'"''${no_firstquote%\"}"'";' >> "$out"
+    done < "${configfile}"
+    echo "}" >> $out
+  '').outPath;
+in lib.makeOverridable ({
+  # The kernel version
+  version,
+  # The kernel pname (should be set for variants)
+  pname ? "linux",
+  # Position of the Linux build expression
+  pos ? null,
+  # Additional kernel make flags
+  extraMakeFlags ? [],
+  # The name of the kernel module directory
+  # Needs to be X.Y.Z[-extra], so pad with zeros if needed.
+  modDirVersion ? null /* derive from version */,
+  # The kernel source (tarball, git checkout, etc.)
+  src,
+  # a list of { name=..., patch=..., extraConfig=...} patches
+  kernelPatches ? [],
+  # The kernel .config file
+  configfile,
+  # Manually specified nixexpr representing the config
+  # If unspecified, this will be autodetected from the .config
+  config ? lib.optionalAttrs allowImportFromDerivation (readConfig configfile),
+  # Custom seed used for CONFIG_GCC_PLUGIN_RANDSTRUCT if enabled. This is
+  # automatically extended with extra per-version and per-config values.
+  randstructSeed ? "",
+  # Extra meta attributes
+  extraMeta ? {},
+
+  # for module compatibility
+  isZen      ? false,
+  isLibre    ? false,
+  isHardened ? false,
+
+  # Whether to utilize the controversial import-from-derivation feature to parse the config
+  allowImportFromDerivation ? false,
+  # ignored
+  features ? null, lib ? lib_, stdenv ? stdenv_,
+}:
+
+let
+  # Provide defaults. Note that we support `null` so that callers don't need to use optionalAttrs,
+  # which can lead to unnecessary strictness and infinite recursions.
+  modDirVersion_ = if modDirVersion == null then lib.versions.pad 3 version else modDirVersion;
+in
+let
+  # Shadow the un-defaulted parameter; don't want null.
+  modDirVersion = modDirVersion_;
+  inherit (lib)
+    hasAttr getAttr optional optionals optionalString optionalAttrs maintainers platforms;
+
+  drvAttrs = config_: kernelConf: kernelPatches: configfile:
+    let
+      # Folding in `ubootTools` in the default nativeBuildInputs is problematic, as
+      # it makes updating U-Boot cumbersome, since it will go above the current
+      # threshold of rebuilds
+      #
+      # To prevent these needless rounds of staging for U-Boot builds, we can
+      # limit the inclusion of ubootTools to target platforms where uImage *may*
+      # be produced.
+      #
+      # This command lists those (kernel-named) platforms:
+      #     .../linux $ grep -l uImage ./arch/*/Makefile | cut -d'/' -f3 | sort
+      #
+      # This is still a guesstimation, but since none of our cached platforms
+      # coincide in that list, this gives us "perfect" decoupling here.
+      linuxPlatformsUsingUImage = [
+        "arc"
+        "arm"
+        "csky"
+        "mips"
+        "powerpc"
+        "sh"
+        "sparc"
+        "xtensa"
+      ];
+      needsUbootTools =
+        lib.elem stdenv.hostPlatform.linuxArch linuxPlatformsUsingUImage
+      ;
+
+      config = let attrName = attr: "CONFIG_" + attr; in {
+        isSet = attr: hasAttr (attrName attr) config;
+
+        getValue = attr: if config.isSet attr then getAttr (attrName attr) config else null;
+
+        isYes = attr: (config.getValue attr) == "y";
+
+        isNo = attr: (config.getValue attr) == "n";
+
+        isModule = attr: (config.getValue attr) == "m";
+
+        isEnabled = attr: (config.isModule attr) || (config.isYes attr);
+
+        isDisabled = attr: (!(config.isSet attr)) || (config.isNo attr);
+      } // config_;
+
+      isModular = config.isYes "MODULES";
+      withRust = config.isYes "RUST";
+
+      buildDTBs = kernelConf.DTB or false;
+
+      # Dependencies that are required to build kernel modules
+      moduleBuildDependencies = [
+        pahole
+        perl
+        elfutils
+        # module makefiles often run uname commands to find out the kernel version
+        (buildPackages.deterministic-uname.override { inherit modDirVersion; })
+      ]
+      ++ optional (lib.versionAtLeast version "5.13") zstd
+      ++ optionals withRust [ rustc rust-bindgen ]
+      ;
+
+    in (optionalAttrs isModular { outputs = [ "out" "dev" ]; }) // {
+      passthru = rec {
+        inherit version modDirVersion config kernelPatches configfile
+          moduleBuildDependencies stdenv;
+        inherit isZen isHardened isLibre withRust;
+        isXen = lib.warn "The isXen attribute is deprecated. All Nixpkgs kernels that support it now have Xen enabled." true;
+        baseVersion = lib.head (lib.splitString "-rc" version);
+        kernelOlder = lib.versionOlder baseVersion;
+        kernelAtLeast = lib.versionAtLeast baseVersion;
+      };
+
+      inherit src;
+
+      depsBuildBuild = [ buildPackages.stdenv.cc ];
+      nativeBuildInputs = [
+        bison
+        flex
+        perl
+        bc
+        nettools
+        openssl
+        rsync
+        gmp
+        libmpc
+        mpfr
+        elfutils
+        zstd
+        python3Minimal
+        kmod
+        hexdump
+      ] ++ optional  needsUbootTools ubootTools
+        ++ optionals (lib.versionAtLeast version "5.2")  [ cpio pahole zlib ]
+        ++ optionals withRust [ rustc rust-bindgen ];
+
+      RUST_LIB_SRC = lib.optionalString withRust rustPlatform.rustLibSrc;
+
+      # avoid leaking Rust source file names into the final binary, which adds
+      # a false dependency on rust-lib-src on targets with uncompressed kernels
+      KRUSTFLAGS = lib.optionalString withRust "--remap-path-prefix ${rustPlatform.rustLibSrc}=/";
+
+      # patches =
+      #   map (p: p.patch) kernelPatches
+      #   # Required for deterministic builds along with some postPatch magic.
+      #   ++ optional (lib.versionOlder version "5.19") ./randstruct-provide-seed.patch
+      #   ++ optional (lib.versionAtLeast version "5.19") ./randstruct-provide-seed-5.19.patch
+      #   # Linux 5.12 marked certain PowerPC-only symbols as GPL, which breaks
+      #   # OpenZFS; this was fixed in Linux 5.19 so we backport the fix
+      #   # https://github.com/openzfs/zfs/pull/13367
+      #   ++ optional (lib.versionAtLeast version "5.12" &&
+      #                lib.versionOlder version "5.19" &&
+      #                stdenv.hostPlatform.isPower)
+      #     (fetchpatch {
+      #       url = "https://git.kernel.org/pub/scm/linux/kernel/git/powerpc/linux.git/patch/?id=d9e5c3e9e75162f845880535957b7fd0b4637d23";
+      #       hash = "sha256-bBOyJcP6jUvozFJU0SPTOf3cmnTQ6ZZ4PlHjiniHXLU=";
+      #     });
+
+      postPatch = ''
+        # Ensure that depmod gets resolved through PATH
+        sed -i Makefile -e 's|= /sbin/depmod|= depmod|'
+
+        # Some linux-hardened patches now remove certain files in the scripts directory, so the file may not exist.
+        [[ -f scripts/ld-version.sh ]] && patchShebangs scripts/ld-version.sh
+
+        # Set randstruct seed to a deterministic but diversified value. Note:
+        # we could have instead patched gen-random-seed.sh to take input from
+        # the buildFlags, but that would require also patching the kernel's
+        # toplevel Makefile to add a variable export. This would be likely to
+        # cause future patch conflicts.
+        for file in scripts/gen-randstruct-seed.sh scripts/gcc-plugins/gen-random-seed.sh; do
+          if [ -f "$file" ]; then
+            substituteInPlace "$file" \
+              --replace NIXOS_RANDSTRUCT_SEED \
+              $(echo ${randstructSeed}${src} ${placeholder "configfile"} | sha256sum | cut -d ' ' -f 1 | tr -d '\n')
+            break
+          fi
+        done
+
+        patchShebangs scripts
+
+        # also patch arch-specific install scripts
+        for i in $(find arch -name install.sh); do
+            patchShebangs "$i"
+        done
+
+        # unset $src because the build system tries to use it and spams a bunch of warnings
+        # see: https://github.com/torvalds/linux/commit/b1992c3772e69a6fd0e3fc81cd4d2820c8b6eca0
+        unset src
+      '';
+
+      configurePhase = ''
+        runHook preConfigure
+
+        mkdir build
+        export buildRoot="$(pwd)/build"
+
+        echo "manual-config configurePhase buildRoot=$buildRoot pwd=$PWD"
+
+        if [ -f "$buildRoot/.config" ]; then
+          echo "Could not link $buildRoot/.config : file exists"
+          exit 1
+        fi
+        ln -sv ${configfile} $buildRoot/.config
+
+        # reads the existing .config file and prompts the user for options in
+        # the current kernel source that are not found in the file.
+        make $makeFlags "''${makeFlagsArray[@]}" oldconfig
+        runHook postConfigure
+
+        make $makeFlags "''${makeFlagsArray[@]}" prepare
+        actualModDirVersion="$(cat $buildRoot/include/config/kernel.release)"
+        if [ "$actualModDirVersion" != "${modDirVersion}" ]; then
+          echo "Error: modDirVersion ${modDirVersion} specified in the Nix expression is wrong, it should be: $actualModDirVersion"
+          exit 1
+        fi
+
+        buildFlagsArray+=("KBUILD_BUILD_TIMESTAMP=$(date -u -d @$SOURCE_DATE_EPOCH)")
+
+        cd $buildRoot
+      '';
+
+      buildFlags = [
+        "KBUILD_BUILD_VERSION=1-PatOS"
+        kernelConf.target
+        "vmlinux"  # for "perf" and things like that
+      ] ++ optional isModular "modules"
+        ++ optionals buildDTBs ["dtbs" "DTC_FLAGS=-@"]
+      ++ extraMakeFlags;
+
+      installFlags = [
+        "INSTALL_PATH=$(out)"
+      ] ++ (optional isModular "INSTALL_MOD_PATH=$(out)")
+      ++ optionals buildDTBs ["dtbs_install" "INSTALL_DTBS_PATH=$(out)/dtbs"];
+
+      dontStrip = true;
+
+      preInstall = let
+        # All we really need to do here is copy the final image and System.map to $out,
+        # and use the kernel's modules_install, firmware_install, dtbs_install, etc. targets
+        # for the rest. Easy, right?
+        #
+        # Unfortunately for us, the obvious way of getting the built image path,
+        # make -s image_name, does not work correctly, because some architectures
+        # (*cough* aarch64 *cough*) change KBUILD_IMAGE on the fly in their install targets,
+        # so we end up attempting to install the thing we didn't actually build.
+        #
+        # Thankfully, there's a way out that doesn't involve just hardcoding everything.
+        #
+        # The kernel has an install target, which runs a pretty simple shell script
+        # (located at scripts/install.sh or arch/$arch/boot/install.sh, depending on
+        # which kernel version you're looking at) that tries to do something sensible.
+        #
+        # (it would be great to hijack this script immediately, as it has all the
+        #   information we need passed to it and we don't need it to try and be smart,
+        #   but unfortunately, the exact location of the scripts differs between kernel
+        #   versions, and they're seemingly not considered to be public API at all)
+        #
+        # One of the ways it tries to discover what "something sensible" actually is
+        # is by delegating to what's supposed to be a user-provided install script
+        # located at ~/bin/installkernel.
+        #
+        # (the other options are:
+        #   - a distribution-specific script at /sbin/installkernel,
+        #        which we can't really create in the sandbox easily
+        #   - an architecture-specific script at arch/$arch/boot/install.sh,
+        #        which attempts to guess _something_ and usually guesses very wrong)
+        #
+        # More specifically, the install script exec's into ~/bin/installkernel, if one
+        # exists, with the following arguments:
+        #
+        # $1: $KERNELRELEASE - full kernel version string
+        # $2: $KBUILD_IMAGE - the final image path
+        # $3: System.map - path to System.map file, seemingly hardcoded everywhere
+        # $4: $INSTALL_PATH - path to the destination directory as specified in installFlags
+        #
+        # $2 is exactly what we want, so hijack the script and use the knowledge given to it
+        # by the makefile overlords for our own nefarious ends.
+        #
+        # Note that the makefiles specifically look in ~/bin/installkernel, and
+        # writeShellScriptBin writes the script to <store path>/bin/installkernel,
+        # so HOME needs to be set to just the store path.
+        #
+        # FIXME: figure out a less roundabout way of doing this.
+        installkernel = buildPackages.writeShellScriptBin "installkernel" ''
+          cp -av $2 $4
+          cp -av $3 $4
+        '';
+      in ''
+        installFlagsArray+=("-j$NIX_BUILD_CORES")
+        export HOME=${installkernel}
+      '';
+
+      # Some image types need special install targets (e.g. uImage is installed with make uinstall on arm)
+      installTargets = [
+        (kernelConf.installTarget or (
+          /**/ if kernelConf.target == "uImage" && stdenv.hostPlatform.linuxArch == "arm" then "uinstall"
+          else if kernelConf.target == "zImage" || kernelConf.target == "Image.gz" || kernelConf.target == "vmlinuz.efi" then "zinstall"
+          else "install"))
+      ];
+
+      # We remove a bunch of stuff that is symlinked from other places to save space,
+      # which trips the broken symlink check. So, just skip it. We'll know if it explodes.
+      dontCheckForBrokenSymlinks = true;
+
+      postInstall = optionalString isModular ''
+        mkdir -p $dev
+        cp vmlinux $dev/
+        if [ -z "''${dontStrip-}" ]; then
+          installFlagsArray+=("INSTALL_MOD_STRIP=1")
+        fi
+        make modules_install $makeFlags "''${makeFlagsArray[@]}" \
+          $installFlags "''${installFlagsArray[@]}"
+        unlink $out/lib/modules/${modDirVersion}/build
+        rm -f $out/lib/modules/${modDirVersion}/source
+
+        mkdir -p $dev/lib/modules/${modDirVersion}/{build,source}
+
+        # To save space, exclude a bunch of unneeded stuff when copying.
+        (cd .. && rsync --archive --prune-empty-dirs \
+            --exclude='/build/' \
+            * $dev/lib/modules/${modDirVersion}/source/)
+
+        cd $dev/lib/modules/${modDirVersion}/source
+
+        cp $buildRoot/{.config,Module.symvers} $dev/lib/modules/${modDirVersion}/build
+        make modules_prepare $makeFlags "''${makeFlagsArray[@]}" O=$dev/lib/modules/${modDirVersion}/build
+
+        # For reproducibility, removes accidental leftovers from a `cc1` call
+        # from a `try-run` call from the Makefile
+        rm -f $dev/lib/modules/${modDirVersion}/build/.[0-9]*.d
+
+        # Keep some extra files on some arches (powerpc, aarch64)
+        for f in arch/powerpc/lib/crtsavres.o arch/arm64/kernel/ftrace-mod.o; do
+          if [ -f "$buildRoot/$f" ]; then
+            cp $buildRoot/$f $dev/lib/modules/${modDirVersion}/build/$f
+          fi
+        done
+
+        # !!! No documentation on how much of the source tree must be kept
+        # If/when kernel builds fail due to missing files, you can add
+        # them here. Note that we may see packages requiring headers
+        # from drivers/ in the future; it adds 50M to keep all of its
+        # headers on 3.10 though.
+
+        chmod u+w -R ..
+        arch=$(cd $dev/lib/modules/${modDirVersion}/build/arch; ls)
+
+        # Remove unused arches
+        for d in $(cd arch/; ls); do
+          if [ "$d" = "$arch" ]; then continue; fi
+          if [ "$arch" = arm64 ] && [ "$d" = arm ]; then continue; fi
+          rm -rf arch/$d
+        done
+
+        # Remove all driver-specific code (50M of which is headers)
+        rm -fR drivers
+
+        # Keep all headers
+        find .  -type f -name '*.h' -print0 | xargs -0 -r chmod u-w
+
+        # Keep linker scripts (they are required for out-of-tree modules on aarch64)
+        find .  -type f -name '*.lds' -print0 | xargs -0 -r chmod u-w
+
+        # Keep root and arch-specific Makefiles
+        chmod u-w Makefile arch/"$arch"/Makefile*
+
+        # Keep whole scripts dir
+        chmod u-w -R scripts
+
+        # Delete everything not kept
+        find . -type f -perm -u=w -print0 | xargs -0 -r rm
+
+        # Delete empty directories
+        find -empty -type d -delete
+      '';
+
+      requiredSystemFeatures = [ "big-parallel" ];
+
+      meta = {
+        # https://github.com/NixOS/nixpkgs/pull/345534#issuecomment-2391238381
+        broken = withRust && lib.versionOlder version "6.12";
+
+        description =
+          "The Linux kernel" +
+          (if kernelPatches == [] then "" else
+            " (with patches: "
+            + lib.concatStringsSep ", " (map (x: x.name) kernelPatches)
+            + ")");
+        license = lib.licenses.gpl2Only;
+        homepage = "https://www.kernel.org/";
+        maintainers = lib.teams.linux-kernel.members ++ [
+          maintainers.thoughtpolice
+        ];
+        platforms = platforms.linux;
+        badPlatforms =
+          lib.optionals (lib.versionOlder version "4.15") [ "riscv32-linux" "riscv64-linux" ] ++
+          lib.optional (lib.versionOlder version "5.19") "loongarch64-linux";
+        timeout = 14400; # 4 hours
+      } // extraMeta;
+    };
+
+  # Absolute paths for compilers avoid any PATH-clobbering issues.
+  commonMakeFlags = [
+    "ARCH=${stdenv.hostPlatform.linuxArch}"
+    "CROSS_COMPILE=${stdenv.cc.targetPrefix}"
+  ] ++ lib.optionals (stdenv.isx86_64 && stdenv.cc.bintools.isLLVM) [
+    # The wrapper for ld.lld breaks linking the kernel. We use the
+    # unwrapped linker as workaround. See:
+    #
+    # https://github.com/NixOS/nixpkgs/issues/321667
+    "LD=${stdenv.cc.bintools.bintools}/bin/${stdenv.cc.targetPrefix}ld"
+  ] ++ (stdenv.hostPlatform.linux-kernel.makeFlags or [])
+    ++ extraMakeFlags;
+in
+
+stdenv.mkDerivation (
+  builtins.foldl' lib.recursiveUpdate {} [
+    (drvAttrs config stdenv.hostPlatform.linux-kernel kernelPatches configfile)
+    {
+      inherit pname version;
+
+      enableParallelBuilding = true;
+
+      hardeningDisable = [ "bindnow" "format" "fortify" "stackprotector" "pic" "pie" ];
+
+      makeFlags = [
+        "O=$(buildRoot)"
+      ] ++ commonMakeFlags;
+
+      passthru = { inherit commonMakeFlags; };
+
+      karch = stdenv.hostPlatform.linuxArch;
+    }
+    (optionalAttrs (pos != null) { inherit pos; })
+  ]
+))
diff --git a/pkgs/kernel/result b/pkgs/kernel/result
new file mode 120000
index 0000000..adacbb4
--- /dev/null
+++ b/pkgs/kernel/result
@@ -0,0 +1 @@
+/nix/store/kwigngi2rkbhd5qmhjaxla2wh3adm4ph-linux-6.13.4-patos1
\ No newline at end of file
diff --git a/pkgs/openssl/default.nix b/pkgs/openssl/default.nix
index 0e1f742..bc833cc 100644
--- a/pkgs/openssl/default.nix
+++ b/pkgs/openssl/default.nix
@@ -92,7 +92,7 @@ stdenv.mkDerivation rec {
     configureFlags =
       [
         "shared" # "shared" builds both shared and static libraries
-        "--prefix=/usr"
+        "--prefix=/"
         "--libdir=lib"
         "--openssldir=/etc/ssl"
       ]
diff --git a/pkgs/rootfs/default.nix b/pkgs/rootfs/default.nix
index c7f0dba..d3c39c3 100644
--- a/pkgs/rootfs/default.nix
+++ b/pkgs/rootfs/default.nix
@@ -7,10 +7,12 @@
 }:
 let
   pname = "patos-rootfs";
+  defaultPassword = "patos";
 in
 stdenvNoCC.mkDerivation (finalAttrs: {
   inherit version;
   inherit pname;
+  inherit defaultPassword;
 
   buildInputs = with pkgs; [
     glibc
@@ -20,7 +22,7 @@ stdenvNoCC.mkDerivation (finalAttrs: {
   glibcPatos = patosPkgs.glibc.out;
   systemd = patosPkgs.systemd.out;
   dbusBroker = patosPkgs.dbus-broker.out;
-  kernel = patosPkgs.kernel.kernel;
+  kernel = patosPkgs.kernel;
   busybox = patosPkgs.busybox.out;
   kmodLibs = pkgs.kmod.lib;
   kmodBin = pkgs.kmod.out;
diff --git a/pkgs/rootfs/mkrootfs.sh b/pkgs/rootfs/mkrootfs.sh
index 14f4dac..7e8df9e 100644
--- a/pkgs/rootfs/mkrootfs.sh
+++ b/pkgs/rootfs/mkrootfs.sh
@@ -62,6 +62,7 @@ Type=root
 SizeMaxBytes=256M
 SizeMinBytes=256M
 EOF
+
 cat <<EOF > $out/etc/repart.d/22-root-verify-a.conf
 [Partition]
 Type=root-verity
@@ -77,6 +78,7 @@ SizeMaxBytes=256M
 SizeMinBytes=256M
 ReadOnly=1
 EOF
+
 cat <<EOF > $out/etc/repart.d/32-root-verity-b.conf
 [Partition]
 Type=root-verity
@@ -90,13 +92,15 @@ cat <<EOF > $out/etc/repart.d/40-var.conf
 [Partition]
 Type=var
 Format=btrfs
-MakeDirectories=/var/lib/confexts /var/.snapshots
+MakeDirectories=/var/lib/confexts /var/lib/extensions /var/lib/portables /var/.snapshots
 MountPoint=/var
 Label=patos-state
 Encrypt=tpm2
 EncryptedVolume=patos-state:none:tpm2-device=auto,luks,discard
-Subvolumes=/var/lib/confexts /var/.snapshots
+Subvolumes=/var/lib/confexts /var/lib/extensions /var/lib/portables /var/.snapshots
 MountPoint=/var/lib/confexts:subvol=/var/lib/confexts
+MountPoint=/var/lib/extensions:subvol=/var/lib/extensions
+MountPoint=/var/lib/portables:subvol=/var/lib/portables
 MountPoint=/var/.snapshots:subvol=/var/.snapshots
 SizeMinBytes=1G
 Minimize=off
@@ -116,13 +120,9 @@ EOF
 cp -P $glibcPatos/lib/*.so* $out/usr/lib/
 
 ### install openssl
-cp -P $openssl/usr/lib/*.so* $out/usr/lib/
+cp -P $openssl/lib/*.so* $out/usr/lib/
 cp -Pr $openssl/etc/ssl $out/etc/
 
-### install kernel modules
-cp -r $kernel/lib/modules $out/usr/lib/
-find $out/usr/lib/modules -type d -exec chmod 755 {} \;
-
 ### install busybox
 cp $busybox/bin/busybox $out/usr/bin/
 $out/usr/bin/busybox --list | xargs -I {} ln -sf busybox $out/usr/bin/{}
@@ -150,11 +150,13 @@ cp -P $kmodLibs/lib/*.so* $out/usr/lib/
 cp -P $kmodBin/bin/* $out/usr/bin
 
 ### install libbpf
-cp -P $libbpf/lib/libbpf* $out/usr/lib
+cp -P $libbpf/lib/libbpf*.so* $out/usr/lib
 
 ### install ca cert bundle
-chmod 755 $out/etc/ssl
+chmod 755 $out/etc/ssl $out/etc/ssl/certs
 cp -P $cacert/etc/ssl/certs/ca-bundle.crt $out/etc/ssl/cert.pem
+ln -sf ../cert.pem $out/etc/ssl/certs/ca-certificates.crt
+ln -sf ../cert.pem $out/etc/ssl/certs/ca-bundle.crt
 
 # setup default files
 $systemd/usr/bin/systemd-hwdb --root=$out --usr update
@@ -162,6 +164,13 @@ $systemd/usr/bin/systemd-tmpfiles --root=$out $out/usr/lib/tmpfiles.d/etc.conf -
 cp $out/usr/share/factory/etc/nsswitch.conf $out/etc/
 cp $out/usr/share/factory/etc/locale.conf $out/etc/
 cp $out/usr/share/factory/etc/vconsole.conf $out/etc/
+# install sys users
+mkdir creds
+echo -n $defaultPassword > creds/passwd.plaintext-password.root
+CREDENTIALS_DIRECTORY=$PWD/creds SYSTEMD_CRYPT_PREFIX='$6$' $systemd/usr/bin/systemd-sysusers --root=$out rootfs/usr/lib/sysusers.d/*.conf
+chmod 600 $out/etc/shadow
+rm -rf creds
+
 
 # Ephemeral machine-id until registration
 ln -sf /run/machine-id $out/etc/machine-id
@@ -171,7 +180,7 @@ rm -rf $out/usr/lib/pkgconfig
 
 ### Find and install all shared libs
 find $out -type f -executable -exec ldd {} \; | awk '{print $3}' | \
-  grep -v systemd | grep -v glibc | grep -v openssl | grep -v tpm2 | grep -v devmapper | grep -v not | \
+  grep -vE "(systemd|glibc|openssl|tpm2|devmapper)" | \
   sort -u | xargs -I {} cp {} $out/usr/lib/
 
 find $out -type f -executable -exec chmod 755 {} \;
@@ -184,3 +193,8 @@ patchelf --remove-rpath $out/usr/lib/ld-linux-x86-64.so.2
 # strip binaries
 find $out -type f -executable -exec strip {} \;
 find $out -type d -exec chmod 755 {} \;
+
+### install kernel modules
+cp -r $kernel/lib/modules $out/usr/lib/
+find $out/usr/lib/modules -type d -exec chmod 755 {} \;
+