nixseparatedebuginfod2: init package and module (#428845)

This commit is contained in:
Martin Weinelt
2025-08-10 15:46:23 +02:00
committed by GitHub
8 changed files with 275 additions and 32 deletions

View File

@@ -1,4 +1,9 @@
{ config, lib, ... }:
{
config,
lib,
pkgs,
...
}:
{
options = {
@@ -23,18 +28,40 @@
'';
};
};
environment.debuginfodServers = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
description = ''
List of urls of debuginfod servers for tools like {command}`gdb` and {command}`valgrind` to use.
config = lib.mkIf config.environment.enableDebugInfo {
# FIXME: currently disabled because /lib is already in
# environment.pathsToLink, and we can't have both.
#environment.pathsToLink = [ "/lib/debug/.build-id" ];
environment.extraOutputsToInstall = [ "debug" ];
environment.variables.NIX_DEBUG_INFO_DIRS = [ "/run/current-system/sw/lib/debug" ];
Unrelated to {option}`environment.enableDebugInfo`.
'';
};
};
config = lib.mkMerge [
(lib.mkIf config.environment.enableDebugInfo {
# FIXME: currently disabled because /lib is already in
# environment.pathsToLink, and we can't have both.
#environment.pathsToLink = [ "/lib/debug/.build-id" ];
environment.extraOutputsToInstall = [ "debug" ];
environment.variables.NIX_DEBUG_INFO_DIRS = [ "/run/current-system/sw/lib/debug" ];
})
(lib.mkIf (config.environment.debuginfodServers != [ ]) {
environment.variables.DEBUGINFOD_URLS = lib.strings.concatStringsSep " " config.environment.debuginfodServers;
environment.systemPackages = [
# valgrind support requires debuginfod-find on PATH
(lib.getBin pkgs.elfutils)
];
environment.etc."gdb/gdbinit.d/nixseparatedebuginfod2.gdb".text = "set debuginfod enabled on";
})
];
}

View File

@@ -591,6 +591,7 @@
./services/development/jupyterhub/default.nix
./services/development/livebook.nix
./services/development/lorri.nix
./services/development/nixseparatedebuginfod2.nix
./services/development/nixseparatedebuginfod.nix
./services/development/rstudio-server/default.nix
./services/development/vsmartcard-vpcd.nix

View File

@@ -101,14 +101,6 @@ in
extra-allowed-users = [ "nixseparatedebuginfod" ];
};
environment.variables.DEBUGINFOD_URLS = "http://${url}";
environment.systemPackages = [
# valgrind support requires debuginfod-find on PATH
(lib.getBin pkgs.elfutils)
];
environment.etc."gdb/gdbinit.d/nixseparatedebuginfod.gdb".text = "set debuginfod enabled on";
environment.debuginfodServers = [ "http://${url}" ];
};
}

View File

@@ -0,0 +1,97 @@
{
pkgs,
lib,
config,
utils,
...
}:
let
cfg = config.services.nixseparatedebuginfod2;
url = "127.0.0.1:${toString cfg.port}";
in
{
options = {
services.nixseparatedebuginfod2 = {
enable = lib.mkEnableOption "nixseparatedebuginfod2, a debuginfod server providing source and debuginfo for nix packages";
port = lib.mkOption {
description = "port to listen";
default = 1950;
type = lib.types.port;
};
package = lib.mkPackageOption pkgs "nixseparatedebuginfod2" { };
substituter = lib.mkOption {
description = "nix substituter to fetch debuginfo from. Either http/https substituters, or `local:` to use debuginfo present in the local store.";
default = "https://cache.nixos.org";
example = "local:";
type = lib.types.str;
};
cacheExpirationDelay = lib.mkOption {
description = "keep unused cache entries for this long. A number followed by a unit";
default = "1d";
type = lib.types.str;
};
};
};
config = lib.mkIf cfg.enable {
systemd.services.nixseparatedebuginfod2 = {
wantedBy = [ "multi-user.target" ];
path = [ config.nix.package ];
serviceConfig = {
ExecStart = [
(utils.escapeSystemdExecArgs [
(lib.getExe cfg.package)
"--listen-address"
url
"--substituter"
cfg.substituter
"--expiration"
cfg.cacheExpirationDelay
])
];
Restart = "on-failure";
CacheDirectory = "nixseparatedebuginfod2";
DynamicUser = true;
# hardening
# Filesystem stuff
ProtectSystem = "strict"; # Prevent writing to most of /
ProtectHome = true; # Prevent accessing /home and /root
PrivateTmp = true; # Give an own directory under /tmp
PrivateDevices = true; # Deny access to most of /dev
ProtectKernelTunables = true; # Protect some parts of /sys
ProtectControlGroups = true; # Remount cgroups read-only
RestrictSUIDSGID = true; # Prevent creating SETUID/SETGID files
PrivateMounts = true; # Give an own mount namespace
RemoveIPC = true;
UMask = "0077";
# Capabilities
CapabilityBoundingSet = ""; # Allow no capabilities at all
NoNewPrivileges = true; # Disallow getting more capabilities. This is also implied by other options.
# Kernel stuff
ProtectKernelModules = true; # Prevent loading of kernel modules
SystemCallArchitectures = "native"; # Usually no need to disable this
SystemCallFilter = "@system-service";
ProtectKernelLogs = true; # Prevent access to kernel logs
ProtectClock = true; # Prevent setting the RTC
ProtectProc = "noaccess";
ProcSubset = "pid";
# Networking
RestrictAddressFamilies = "AF_UNIX AF_INET AF_INET6";
# Misc
LockPersonality = true; # Prevent change of the personality
ProtectHostname = true; # Give an own UTS namespace
RestrictRealtime = true; # Prevent switching to RT scheduling
MemoryDenyWriteExecute = true; # Maybe disable this for interpreters like python
RestrictNamespaces = true;
};
};
environment.debuginfodServers = [ "http://${url}" ];
};
}

View File

@@ -1059,6 +1059,7 @@ in
};
nixpkgs = pkgs.callPackage ../modules/misc/nixpkgs/test.nix { inherit evalMinimalConfig; };
nixseparatedebuginfod = runTest ./nixseparatedebuginfod.nix;
nixseparatedebuginfod2 = runTest ./nixseparatedebuginfod2.nix;
node-red = runTest ./node-red.nix;
nomad = runTest ./nomad.nix;
nominatim = runTest ./nominatim.nix;

View File

@@ -5,7 +5,7 @@ let
in
{
name = "nixseparatedebuginfod";
# A binary cache with debug info and source for nix
# A binary cache with debug info and source for gnumake
nodes.cache =
{ pkgs, ... }:
{
@@ -15,8 +15,8 @@ in
openFirewall = true;
};
system.extraDependencies = [
pkgs.nix.debug
pkgs.nix.src
pkgs.gnumake.debug
pkgs.gnumake.src
pkgs.sl
];
};
@@ -33,9 +33,10 @@ in
environment.systemPackages = [
pkgs.valgrind
pkgs.gdb
pkgs.gnumake
(pkgs.writeShellScriptBin "wait_for_indexation" ''
set -x
while debuginfod-find debuginfo /run/current-system/sw/bin/nix |& grep 'File too large'; do
while debuginfod-find debuginfo /run/current-system/sw/bin/make |& grep 'File too large'; do
sleep 1;
done
'')
@@ -56,27 +57,27 @@ in
# nixseparatedebuginfod needs .drv to associate executable -> source
# on regular systems this would be provided by nixos-rebuild
machine.succeed("nix-instantiate '<nixpkgs>' -A nix")
machine.succeed("nix-instantiate '<nixpkgs>' -A gnumake")
machine.succeed("timeout 600 wait_for_indexation")
# test debuginfod-find
machine.succeed("debuginfod-find debuginfo /run/current-system/sw/bin/nix")
machine.succeed("debuginfod-find debuginfo /run/current-system/sw/bin/make")
# test that gdb can fetch source
out = machine.succeed("gdb /run/current-system/sw/bin/nix --batch -x ${builtins.toFile "commands" ''
out = machine.succeed("gdb /run/current-system/sw/bin/make --batch -x ${builtins.toFile "commands" ''
start
l
''}")
print(out)
assert 'int main(' in out
assert 'main (int argc, char **argv, char **envp)' in out
# test that valgrind can display location information
# this relies on the fact that valgrind complains about nix
# libgc helps in this regard, and we also ask valgrind to show leak kinds
# this relies on the fact that valgrind complains about gnumake
# because we also ask valgrind to show leak kinds
# which are usually false positives.
out = machine.succeed("valgrind --leak-check=full --show-leak-kinds=all nix-env --version 2>&1")
out = machine.succeed("valgrind --leak-check=full --show-leak-kinds=all make --version 2>&1")
print(out)
assert 'main.cc' in out
assert 'main.c' in out
'';
}

View File

@@ -0,0 +1,72 @@
{ pkgs, lib, ... }:
{
name = "nixseparatedebuginfod2";
# A binary cache with debug info and source for gnumake
nodes.cache =
{ pkgs, ... }:
{
services.nginx = {
enable = true;
virtualHosts.default = {
default = true;
addSSL = false;
root = "/var/lib/thebinarycache";
};
};
networking.firewall.allowedTCPPorts = [ 80 ];
systemd.services.buildthebinarycache = {
before = [ "nginx.service" ];
wantedBy = [ "nginx.service" ];
script = ''
${pkgs.nix}/bin/nix --extra-experimental-features nix-command copy --to file:///var/lib/thebinarycache?index-debug-info=true ${pkgs.gnumake.debug} ${pkgs.gnumake} ${pkgs.gnumake.src} ${pkgs.sl}
'';
serviceConfig = {
User = "nginx";
Group = "nginx";
StateDirectory = "thebinarycache";
Type = "oneshot";
};
};
};
# the machine where we need the debuginfo
nodes.machine = {
services.nixseparatedebuginfod2 = {
enable = true;
substituter = "http://cache";
};
environment.systemPackages = [
pkgs.valgrind
pkgs.gdb
pkgs.gnumake
];
};
testScript = ''
start_all()
cache.wait_for_unit("nginx.service")
cache.wait_for_open_port(80)
machine.wait_for_unit("nixseparatedebuginfod2.service")
machine.wait_for_open_port(1950)
with subtest("check that the binary cache works"):
machine.succeed("nix-store --extra-substituters http://cache --option require-sigs false -r ${pkgs.sl}")
# test debuginfod-find
machine.succeed("debuginfod-find debuginfo /run/current-system/sw/bin/make")
# test that gdb can fetch source
out = machine.succeed("gdb /run/current-system/sw/bin/make --batch -x ${builtins.toFile "commands" ''
start
l
''}")
print(out)
assert 'main (int argc, char **argv, char **envp)' in out
# test that valgrind can display location information
# this relies on the fact that valgrind complains about gnumake
# because we also ask valgrind to show leak kinds
# which are usually false positives.
out = machine.succeed("valgrind --leak-check=full --show-leak-kinds=all make --version 2>&1")
print(out)
assert 'main.c' in out
'';
}

View File

@@ -0,0 +1,52 @@
{
lib,
fetchFromGitHub,
rustPlatform,
libarchive,
openssl,
pkg-config,
bubblewrap,
elfutils,
nix,
nixosTests,
}:
rustPlatform.buildRustPackage rec {
pname = "nixseparatedebuginfod2";
version = "0.1.0";
src = fetchFromGitHub {
owner = "symphorien";
repo = "nixseparatedebuginfod2";
tag = "v${version}";
hash = "sha256-bk+l/oWAPuWV6mnh9Pr/mru3BZjos08IfzEGUEFSW1E=";
};
cargoHash = "sha256-HmtFso6uF2GsjIA0FPVL4S3S+lwQUrg7N576UaekXpU=";
buildInputs = [
libarchive
openssl
];
nativeBuildInputs = [ pkg-config ];
nativeCheckInputs = [
bubblewrap
elfutils
nix
];
env.OPENSSL_NO_VENDOR = "1";
passthru.tests = { inherit (nixosTests) nixseparatedebuginfod2; };
meta = {
description = "Downloads and provides debug symbols and source code for nix derivations to gdb and other debuginfod-capable debuggers as needed";
homepage = "https://github.com/symphorien/nixseparatedebuginfod2";
license = lib.licenses.gpl3Only;
maintainers = [ lib.maintainers.symphorien ];
platforms = lib.platforms.linux;
mainProgram = "nixseparatedebuginfod2";
};
}