deb: Depends: never gets libc6 (or other shlib deps) for dynamically-linked cgo binaries #74

Open
opened 2026-07-19 21:45:51 +02:00 by heiko · 0 comments
Owner

internal/pack/deb builds binary .debs by hand (no dpkg-shlibdeps
invocation), so the ${shlibs:Depends} placeholder in the populated
debian/control stub is never substituted, and spec.Depends only ever
contains what the user explicitly configured.

For a binary built with cgo enabled (Go's default; e.g. anything using
net with the system resolver, os/user, etc.), the resulting ELF is
dynamically linked against libc:

$ ldd usr/bin/joker
    linux-vdso.so.1
    libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6
    /lib64/ld-linux-x86-64.so.2

but the generated package's control file has no Depends: line at all
referencing it:

$ dpkg-deb -e pkg.deb /tmp/ctrl && cat /tmp/ctrl/control
Package: joker-dmapi-client
...
Description: ...
 No extended description available.

lintian correctly flags this:

W: joker-dmapi-client: undeclared-elf-prerequisites (libc.so.6) [usr/bin/joker]

Reproduction

Package any Go binary built with default CGO_ENABLED=1 (the Go
default) that links dynamically -- e.g. go.schlittermann.de/ius/joker-dmapi-client,
cmd/joker. Run lintian on the resulting .deb.

Notes

  • Setting CGO_ENABLED=0 in the project's env: section to force a
    static binary was tried as a workaround and made things worse: it
    trades this warning (and the two PIE/RELRO ones, see the companion
    issue) for a harder lintian error, statically-linked-binary. So
    that's not a viable per-project fix on its own.
  • cert-proxy-client/cert-proxy-server already use exactly that
    CGO_ENABLED: 0 + a hand-written debian/.lintian-overrides
    suppressing statically-linked-binary. That's a working pattern today,
    but it has to be hand-rolled per project; gogogo's populate command
    doesn't scaffold a lintian-overrides stub.
  • A real fix for the dynamic-linking case likely needs one of:
    • after building the data.tar.gz payload, run the built ELF binaries
      through debug/elf to collect DT_NEEDED entries and translate known
      SONAMEs to Debian package names (at minimum libc.so.6 -> libc6),
      merging into spec.Depends; or
    • shell out to dpkg-shlibdeps against the staged package tree, the
      same way debhelper does it, if a bundled/manual ELF-to-package
      mapping is considered too fragile long-term.
  • Static (CGO_ENABLED=0) builds should probably remain a supported,
    documented option too (avoiding this whole class of finding), but
    see the companion issue about statically-linked-binary.
internal/pack/deb builds binary .debs by hand (no dpkg-shlibdeps invocation), so the ${shlibs:Depends} placeholder in the populated debian/control stub is never substituted, and spec.Depends only ever contains what the user explicitly configured. For a binary built with cgo enabled (Go's default; e.g. anything using net with the system resolver, os/user, etc.), the resulting ELF is dynamically linked against libc: $ ldd usr/bin/joker linux-vdso.so.1 libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 but the generated package's control file has no Depends: line at all referencing it: $ dpkg-deb -e pkg.deb /tmp/ctrl && cat /tmp/ctrl/control Package: joker-dmapi-client ... Description: ... No extended description available. lintian correctly flags this: W: joker-dmapi-client: undeclared-elf-prerequisites (libc.so.6) [usr/bin/joker] ### Reproduction Package any Go binary built with default CGO_ENABLED=1 (the Go default) that links dynamically -- e.g. go.schlittermann.de/ius/joker-dmapi-client, cmd/joker. Run lintian on the resulting .deb. ### Notes - Setting CGO_ENABLED=0 in the project's env: section to force a static binary was tried as a workaround and made things worse: it trades this warning (and the two PIE/RELRO ones, see the companion issue) for a harder lintian error, statically-linked-binary. So that's not a viable per-project fix on its own. - cert-proxy-client/cert-proxy-server already use exactly that CGO_ENABLED: 0 + a hand-written debian/<pkg>.lintian-overrides suppressing statically-linked-binary. That's a working pattern today, but it has to be hand-rolled per project; gogogo's `populate` command doesn't scaffold a lintian-overrides stub. - A real fix for the dynamic-linking case likely needs one of: - after building the data.tar.gz payload, run the built ELF binaries through debug/elf to collect DT_NEEDED entries and translate known SONAMEs to Debian package names (at minimum libc.so.6 -> libc6), merging into spec.Depends; or - shell out to dpkg-shlibdeps against the staged package tree, the same way debhelper does it, if a bundled/manual ELF-to-package mapping is considered too fragile long-term. - Static (CGO_ENABLED=0) builds should probably remain a supported, documented option too (avoiding this whole class of finding), but see the companion issue about statically-linked-binary.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
heiko/gogogo#74
No description provided.