One Missing Dependency Broke Three Unrelated Packages, Silently

Three unrelated packages on this from-scratch Linux build each shipped with a real, working-looking installation that was actually missing a feature — the same feature, in every case, for the same reason. systemd, shadow, and NetworkManager were each built before Linux-PAM existed anywhere on the system, and each one's own build-time detection quietly concluded "PAM isn't here" and moved on without it. Three separate bugs, three separate rebuild passes, one root cause: build order.

systemd: a login that never registers a session

systemd's first build pass ran with -D pamconfdir=no, at a point in the build sequence where Linux-PAM hadn't been installed yet. Meson's own dependency check for PAM support failed cleanly — no error, just a logged message: "Skipping pam_systemd.8 because HAVE_PAM is false." The practical effect only shows up later, at login: pam_systemd.so, the module responsible for registering a new login with systemd-logind, was never built at all. Without it, logging in never creates a logind session, and XDG_RUNTIME_DIR — the per-user runtime directory that, among other things, every Wayland compositor requires to create its display socket — never gets created either. Nothing about a failed ninja install or a missing binary; systemd installed exactly what it was told to, minus a feature nobody had a way to ask for yet.

shadow: login and su with no PAM support at all

Shadow's configure auto-detects PAM the same way Qt6's build auto-detects Fontconfig elsewhere in this project: default to "yes" if found, silently "no" otherwise. Shadow's first build ran before Linux-PAM existed, so its own --with-libpam detection found nothing and both login and su got built without any PAM support whatsoever. The check that actually proves it is a one-line, no-ambiguity command: readelf -d /bin/login lists that binary's dynamic dependencies, and on the first build it showed only libcrypt and libc — no libpam anywhere in the list. A binary that links against PAM correctly shows it right there in its own dependency table; one that doesn't, doesn't, and there's no runtime symptom short of actually trying to use a PAM-aware login feature that would tell you which one you have.

NetworkManager: a network daemon nobody's allowed to talk to

NetworkManager was deliberately built early too, but for a different reason: it only existed at that point so that libnm was available for networkmanager-qt and plasma-workspace to compile against, well before Plasma itself was anywhere near ready to run. That first build shipped with polkit=false and modem_manager=false, both correct at the time, because neither Polkit nor ModemManager existed yet either. The problem only became visible once Plasma's own network applet, plasma-nm, needed a real, policy-authorized NetworkManager daemon to actually talk to — without Polkit, there's no mechanism for an ordinary desktop session to perform a normal network operation like connecting to wifi without being root.

Same fix shape, three times

Each package's fix was a straight rebuild with the same source and, for systemd and shadow, the exact same configuration — the only thing that changed between the broken build and the working one was that Linux-PAM now existed on disk when the build's own detection logic ran. No patches, no workarounds, nothing to actually reason about at the code level. The fix wasn't fixing a bug in systemd, shadow, or NetworkManager; each of the three was working exactly as designed, correctly reporting the absence of a dependency that wasn't there yet. The actual bug was a build order that asked three different packages the same question — "is PAM available?" — before the honest answer had a chance to be yes.

What this costs when it's not caught

None of the three failures announced themselves at build time. systemd's meson output logged a skip message that reads as informational, not urgent. Shadow's configure silently chose the "no PAM" branch without printing anything alarming at all. NetworkManager built and ran fine — its own daemon doesn't need Polkit to start, only to authorize specific operations a caller doesn't have root for. Every one of these looks, from a build log, exactly like a package that installed successfully, because it did. The only way any of the three surfaces is symptom-first — a login that doesn't create a runtime directory, an su that can't be configured through PAM, a network applet that can't get authorization — and none of those symptoms point back at "build order" as the explanation on their own. Catching the pattern took noticing the same shape three times: not three unrelated bugs, one dependency that arrived late enough to be silently missed by everything that asked for it before it showed up.

Add new comment

Restricted HTML

  • Allowed HTML tags: <a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.
Please share this article on your favorite website or platform.