Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 0649757570e8
Choose a base ref
...
head repository: NixOS/nixpkgs
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 4d36ba1d4391
Choose a head ref
  • 3 commits
  • 2 files changed
  • 2 contributors

Commits on Jan 3, 2021

  1. systemd: patch runtime dlopen calls

    This ensures that all the features that are implemented via dlopen(3)
    are available (or explicitly deactivated) by pointing dlopen to the
    absolute store path instead of relying on the linkers runtime lookup
    code.
    
    All of the dlopen calls have to be handled. When new ones are introduced
    by upstream (or one of our patches) those must be explicitly declared,
    otherwise the build will fail.
    
    As of systemd version 247 we've seen a few errors like `libpcre2.… not
    found` when using e.g. --grep with journalctl. Those errors should
    become less unexpected now.
    
    There are generally two classes of dlopen calls. Those that we want to
    support and those that should be deactivated / unsupported. This change
    enforces that we handle all dlopen calls explicitly. Meaning: There is
    not a single dlopen call in the code source tree that we did not
    explicitly handle.
    
    In order to do this I introduced a list of attributes that maps from
    shared object name to the package that contains them. The package can be
    null meaning the reference should be nuked and the shared object will
    never be loadable during runtime (because it points at an invalid store
    path location).
    andir committed Jan 3, 2021

    Verified

    This commit was signed with the committer’s verified signature. The key has expired.
    erictapen Kerstin
    Copy the full SHA
    494ed4d View commit details
  2. nixos/tests/systemd-journal: ensure that --grep works

    Previously, after the version bump to v247, we broke journalctl --grep
    as libpcre2 was lazily loaded during runtime using dlopen(3). This
    ensures that we have a test case that alerts us when it fails again.
    andir committed Jan 3, 2021
    Copy the full SHA
    37539e7 View commit details
  3. Merge pull request #108032 from andir/systemd-dlopen

    systemd: patch runtime dlopen calls
    flokli authored Jan 3, 2021
    Copy the full SHA
    4d36ba1 View commit details
Showing with 86 additions and 0 deletions.
  1. +2 −0 nixos/tests/systemd-journal.nix
  2. +84 −0 pkgs/os-specific/linux/systemd/default.nix
2 changes: 2 additions & 0 deletions nixos/tests/systemd-journal.nix
Original file line number Diff line number Diff line change
@@ -13,6 +13,8 @@ import ./make-test-python.nix ({ pkgs, ... }:
testScript = ''
machine.wait_for_unit("multi-user.target")
machine.succeed("journalctl --grep=systemd")
machine.succeed(
"${pkgs.curl}/bin/curl -s localhost:19531/machine | ${pkgs.jq}/bin/jq -e '.hostname == \"machine\"'"
)
84 changes: 84 additions & 0 deletions pkgs/os-specific/linux/systemd/default.nix
Original file line number Diff line number Diff line change
@@ -160,6 +160,90 @@ stdenv.mkDerivation {
--replace \
"find_program('objcopy'" \
"find_program('${stdenv.cc.bintools.targetPrefix}objcopy'"
'' + (let

# The folllowing dlopen patches ensure that all the features that are
# implemented via dlopen(3) are available (or explicitly deactivated) by
# pointing dlopen to the absolute store path instead of relying on the
# linkers runtime lookup code.
#
# All of the dlopen calls have to be handled. When new ones are introduced
# by upstream (or one of our patches) they must be explicitly declared,
# otherwise the build will fail.
#
# As of systemd version 247 we've seen a few errors like `libpcre2.… not
# found` when using e.g. --grep with journalctl. Those errors should
# become less unexpected now.
#
# There are generally two classes of dlopen(3) calls. Those that we want to
# support and those that should be deactivated / unsupported. This change
# enforces that we handle all dlopen calls explicitly. Meaning: There is
# not a single dlopen call in the source code tree that we did not
# explicitly handle.
#
# In order to do this we introduced a list of attributes that maps from
# shared object name to the package that contains them. The package can be
# null meaning the reference should be nuked and the shared object will
# never be loadable during runtime (because it points at an invalid store
# path location).
#
# To get a list of dynamically loaded libraries issue something like
# `grep -ri 'dlopen("lib' $src` and update the below list.
dlopenLibs = [
# We did never provide support for libxkbcommon & qrencode
{ name = "libxkbcommon.so.0"; pkg = null; }
{ name = "libqrencode.so.4"; pkg = null; }

# We did not provide libpwquality before so it is safe to disable it for
# now.
{ name = "libpwquality.so.1"; pkg = null; }

# Only include cryptsetup if it is enabled. We might not be able to
# provide it during "bootstrap" in e.g. the minimal systemd build as
# cryptsetup has udev (aka systemd) in it's dependencies.
{ name = "libcryptsetup.so.12"; pkg = if withCryptsetup then cryptsetup else null; }

# We are using libidn2 so we only provide that and ignore the others.
# Systemd does this decision during configure time and uses ifdef's to
# enable specific branches. We can safely ignore (nuke) the libidn "v1"
# libraries.
{ name = "libidn2.so.0"; pkg = libidn2; }
{ name = "libidn.so.12"; pkg = null; }
{ name = "libidn.so.11"; pkg = null; }

# journalctl --grep requires libpcre so lets provide it
{ name = "libpcre2-8.so.0"; pkg = pcre2; }
];

patchDlOpen = dl: let
library = "${lib.makeLibraryPath [dl.pkg]}/${dl.name}";
in if dl.pkg == null then ''
# remove the dependency on the library by replacing it with an invalid path
for file in $(grep -lr 'dlopen("${dl.name}"' src); do
echo "patching dlopen(\"${dl.name}\", …) in $file to an invalid store path ("/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-not-implemented/${dl.name}")…"
substituteInPlace "$file" --replace 'dlopen("${dl.name}"' 'dlopen("/nix/store/eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee-not-implemented/${dl.name}"'
done
'' else ''
# ensure that the library we provide actually exists
if ! [ -e ${library} ]; then
echo 'The shared library `${library}` does not exist but was given as subtitute for `${dl.name}`'
exit 1
fi
# make the path to the dependency explicit
for file in $(grep -lr 'dlopen("${dl.name}"' src); do
echo "patching dlopen(\"${dl.name}\", …) in $file to ${library}…"
substituteInPlace "$file" --replace 'dlopen("${dl.name}"' 'dlopen("${library}"'
done
'';
in # patch all the dlopen calls to contain absolute paths to the libraries
lib.concatMapStringsSep "\n" patchDlOpen dlopenLibs)
# finally ensure that there are no left-over dlopen calls that we didn't handle
+ ''
if grep -qr 'dlopen("[^/]' src; then
echo "Found unhandled dlopen calls: "
grep -r 'dlopen("[^/]' src
exit 1
fi
'';

outputs = [ "out" "man" "dev" ];